import streamlit as st from typing import Dict, Any, List from datetime import datetime import pandas as pd from lib.ai_seo_tools.content_calendar.core.content_generator import ContentGenerator from lib.ai_seo_tools.content_calendar.core.ai_generator import AIGenerator from lib.ai_seo_tools.content_calendar.integrations.seo_optimizer import SEOOptimizer from lib.database.models import ContentItem, ContentType, Platform, SEOData import logging from lib.database.models import get_engine, get_session, init_db logger = logging.getLogger('content_calendar.optimization') engine = get_engine() init_db(engine) session = get_session(engine) class OptimizationManager: def __init__(self): if 'optimization_history' not in st.session_state: st.session_state.optimization_history = {} if 'optimization_previews' not in st.session_state: st.session_state.optimization_previews = {} if 'optimization_metrics' not in st.session_state: st.session_state.optimization_metrics = {} def track_optimization(self, content_id: str, optimization_data: Dict[str, Any]) -> bool: """Track optimization changes for content with detailed metrics.""" try: if content_id not in st.session_state.optimization_history: st.session_state.optimization_history[content_id] = [] optimization_data['timestamp'] = datetime.now() optimization_data['metrics'] = self._calculate_optimization_metrics(optimization_data) st.session_state.optimization_history[content_id].append(optimization_data) # Update metrics if content_id not in st.session_state.optimization_metrics: st.session_state.optimization_metrics[content_id] = [] st.session_state.optimization_metrics[content_id].append(optimization_data['metrics']) return True except Exception as e: logger.error(f"Error tracking optimization: {str(e)}") return False def _calculate_optimization_metrics(self, optimization_data: Dict[str, Any]) -> Dict[str, Any]: """Calculate detailed optimization metrics.""" try: metrics = { 'readability_score': 0, 'seo_score': 0, 'engagement_potential': 0, 'keyword_density': 0, 'content_quality': 0 } # Calculate readability score if 'content' in optimization_data: content = optimization_data['content'] metrics['readability_score'] = self._calculate_readability(content) # Calculate SEO score if 'seo_data' in optimization_data: seo_data = optimization_data['seo_data'] metrics['seo_score'] = self._calculate_seo_score(seo_data) metrics['keyword_density'] = self._calculate_keyword_density(seo_data) # Calculate engagement potential if 'engagement_metrics' in optimization_data: engagement = optimization_data['engagement_metrics'] metrics['engagement_potential'] = self._calculate_engagement_potential(engagement) # Calculate overall content quality metrics['content_quality'] = ( metrics['readability_score'] * 0.3 + metrics['seo_score'] * 0.3 + metrics['engagement_potential'] * 0.4 ) return metrics except Exception as e: logger.error(f"Error calculating optimization metrics: {str(e)}") return {} def _calculate_readability(self, content: str) -> float: """Calculate content readability score.""" try: # Implement readability calculation logic # This is a placeholder implementation return 0.8 except Exception as e: logger.error(f"Error calculating readability: {str(e)}") return 0.0 def _calculate_seo_score(self, seo_data: SEOData) -> float: """Calculate SEO optimization score.""" try: # Implement SEO score calculation logic # This is a placeholder implementation return 0.85 except Exception as e: logger.error(f"Error calculating SEO score: {str(e)}") return 0.0 def _calculate_keyword_density(self, seo_data: SEOData) -> float: """Calculate keyword density.""" try: # Implement keyword density calculation logic # This is a placeholder implementation return 2.5 except Exception as e: logger.error(f"Error calculating keyword density: {str(e)}") return 0.0 def _calculate_engagement_potential(self, engagement: Dict[str, Any]) -> float: """Calculate content engagement potential.""" try: # Implement engagement potential calculation logic # This is a placeholder implementation return 0.75 except Exception as e: logger.error(f"Error calculating engagement potential: {str(e)}") return 0.0 def get_optimization_history(self, content_id: str) -> List[Dict[str, Any]]: """Get detailed optimization history for content.""" return st.session_state.optimization_history.get(content_id, []) def get_optimization_metrics(self, content_id: str) -> List[Dict[str, Any]]: """Get optimization metrics history.""" return st.session_state.optimization_metrics.get(content_id, []) def save_preview(self, content_id: str, preview_data: Dict[str, Any]) -> bool: """Save optimization preview with versioning.""" try: if content_id not in st.session_state.optimization_previews: st.session_state.optimization_previews[content_id] = [] preview_data['version'] = len(st.session_state.optimization_previews[content_id]) + 1 preview_data['timestamp'] = datetime.now() st.session_state.optimization_previews[content_id].append(preview_data) return True except Exception as e: logger.error(f"Error saving preview: {str(e)}") return False def get_preview(self, content_id: str, version: int = None) -> Dict[str, Any]: """Get optimization preview with optional versioning.""" try: previews = st.session_state.optimization_previews.get(content_id, []) if not previews: return {} if version is None: return previews[-1] for preview in previews: if preview['version'] == version: return preview return {} except Exception as e: logger.error(f"Error getting preview: {str(e)}") return {} def render_content_optimization( content_generator: ContentGenerator, ai_generator: AIGenerator, seo_optimizer: SEOOptimizer ): """Render the content optimization interface with advanced features.""" st.title("Content Calendar") # Initialize optimization manager optimization_manager = OptimizationManager() # Check if calendar manager is available if 'calendar_manager' not in st.session_state: st.error("Calendar manager not initialized. Please refresh the page.") return # Create main tabs main_tabs = st.tabs(["Content Planning", "Content Optimization"]) with main_tabs[0]: # Create two columns for the layout col1, col2 = st.columns([1, 1]) with col1: st.header("Quick Calendar Generation") st.markdown(""" Generate a content calendar in three simple steps: 1. Enter your keywords 2. Select target platforms 3. Choose time period """) # Step 1: Keywords Input st.subheader("Step 1: Enter Keywords") keywords = st.text_area( "Enter keywords or topics (one per line)", help="Enter the main topics or keywords you want to create content about" ) # Step 2: Platform Selection st.subheader("Step 2: Select Target Platforms") platform_categories = { "Website": ["WEBSITE"], "Social Media": ["INSTAGRAM", "FACEBOOK", "TWITTER", "LINKEDIN"], "Video": ["YOUTUBE"], "Newsletter": ["NEWSLETTER"] } selected_platforms = [] for category, platforms in platform_categories.items(): st.markdown(f"**{category}**") for platform in platforms: if st.checkbox(platform.replace("_", " ").title(), key=f"platform_{platform}"): selected_platforms.append(platform) # Step 3: Time Period st.subheader("Step 3: Choose Time Period") time_period = st.selectbox( "Select time period", ["1 Week", "2 Weeks", "1 Month", "3 Months", "6 Months"], help="Choose how far ahead you want to plan your content" ) # Generate Calendar Button if st.button("Generate with AI", type="primary"): if not keywords or not selected_platforms: st.error("Please enter keywords and select at least one platform.") else: with st.spinner("Generating content calendar..."): try: # Generate content ideas based on keywords content_ideas = [] for keyword in keywords.split('\n'): if keyword.strip(): # Generate content ideas for each platform for platform in selected_platforms: try: # Create a content item for the AI generator content_item = ContentItem( title=keyword.strip(), description=f"Content about {keyword.strip()}", content_type=ContentType.BLOG_POST if platform == "WEBSITE" else ContentType.SOCIAL_MEDIA, platforms=[Platform[platform]], publish_date=datetime.now(), seo_data=SEOData( title=keyword.strip(), meta_description=f"Content about {keyword.strip()}", keywords=[keyword.strip()], structured_data={} ) ) # Generate content using AI generator content_idea = ai_generator.enhance_content( content=content_item, enhancement_type='content_generation', target_audience={ 'content_settings': { 'tone': 'professional', 'length': 'medium', 'engagement_goal': 'awareness', 'creativity_level': 5 } } ) if content_idea: content_ideas.append({ 'title': content_idea.get('title', keyword.strip()), 'introduction': content_idea.get('content', f"Content about {keyword.strip()}"), 'platform': platform, 'meta_description': content_idea.get('meta_description', ''), 'keywords': [keyword.strip()] }) except Exception as e: logger.error(f"Error generating content for {keyword} on {platform}: {str(e)}") continue if content_ideas: # Create calendar entries calendar = st.session_state.calendar_manager.get_calendar() for idea in content_ideas: try: # Create content item content_item = ContentItem( title=idea['title'], description=idea['introduction'], content_type=ContentType.BLOG_POST if idea['platform'] == "WEBSITE" else ContentType.SOCIAL_MEDIA, platforms=[Platform[idea['platform']]], publish_date=datetime.now(), seo_data=SEOData( title=idea['title'], meta_description=idea.get('meta_description', ''), keywords=idea.get('keywords', []), structured_data={} ) ) calendar.add_content(content_item) except Exception as e: logger.error(f"Error adding content to calendar: {str(e)}") continue st.success("Content calendar generated successfully!") st.rerun() # Refresh to show new content else: st.error("Failed to generate any content ideas. Please try different keywords or settings.") except Exception as e: logger.error(f"Error generating content calendar: {str(e)}") st.error("An error occurred while generating the content calendar. Please try again.") with col2: st.header("Scheduled Content") # Get all content from calendar calendar = st.session_state.calendar_manager.get_calendar() if not calendar: st.info("No content scheduled yet. Generate content using the form on the left.") else: # Group content by platform platform_content = {} for item in calendar.get_all_content(): platform = item.platforms[0].name if item.platforms else "Unknown" if platform not in platform_content: platform_content[platform] = [] platform_content[platform].append(item) # Create tabs for each platform platform_tabs = st.tabs(list(platform_content.keys())) for i, (platform, content) in enumerate(platform_content.items()): with platform_tabs[i]: st.write(f"### {platform} Content") # Convert content to DataFrame for better display content_data = [] for item in content: content_data.append({ 'Date': item.publish_date.strftime('%Y-%m-%d'), 'Title': item.title, 'Type': item.content_type.name, 'Status': item.status }) if content_data: df = pd.DataFrame(content_data) st.dataframe(df, use_container_width=True) # Add action buttons for each content item for item in content: with st.expander(f"Actions for: {item.title}"): col1, col2, col3 = st.columns(3) with col1: if st.button("Edit", key=f"edit_{item.title}"): st.session_state.selected_content = item.title with col2: if st.button("Optimize", key=f"optimize_{item.title}"): st.session_state.selected_content = item.title st.session_state.active_tab = "Content Optimization" with col3: if st.button("Delete", key=f"delete_{item.title}"): calendar.remove_content(item) st.success(f"Removed {item.title}") st.rerun() with main_tabs[1]: st.header("Content Optimization") # Get available content calendar = st.session_state.calendar_manager.get_calendar() if not calendar: st.info("No content available for optimization. Use the Content Planning tab to generate content.") return available_content = calendar.get_all_content() content_options = [item.title for item in available_content] # Content selection selected_content = st.selectbox( "Select content to optimize", options=content_options, key="optimize_content_select" ) if selected_content: try: content_item = next( item for item in available_content if item.title == selected_content ) # Create tabs for different optimization aspects opt_tabs = st.tabs(["Content Optimization", "SEO Optimization", "Preview", "History", "Analytics"]) with opt_tabs[0]: st.subheader("Content Optimization") # Show onboarding info if no optimization history if not optimization_manager.get_optimization_history(content_item.title): st.info(""" ### Content Optimization Guide Use these tools to enhance your content: - **Content Tone**: Adjust the writing style to match your brand voice - **Content Length**: Optimize for your target platform's requirements - **Engagement Goal**: Focus on specific audience actions - **Creativity Level**: Balance between creative and professional content Click 'Generate Optimization' to get started! """) # Advanced Optimization Settings col1, col2 = st.columns(2) with col1: tone = st.select_slider( "Content Tone", options=["Professional", "Casual", "Educational", "Entertaining", "Persuasive"], value="Professional" ) length = st.radio( "Content Length", ["Short", "Medium", "Long"], horizontal=True ) with col2: engagement_goal = st.selectbox( "Engagement Goal", ["Awareness", "Consideration", "Conversion", "Retention"] ) creativity_level = st.slider( "Creativity Level", min_value=1, max_value=10, value=5 ) if st.button("Generate Optimization", type="primary"): with st.spinner("Optimizing content..."): try: # Generate optimization optimization = content_generator.optimize_content( content=content_item, tone=tone, length=length, engagement_goal=engagement_goal, creativity_level=creativity_level ) if optimization: st.success("Content optimized successfully!") # Show optimization results st.subheader("Optimization Results") st.write(optimization.get('content', '')) # Save optimization history optimization_manager.track_optimization( content_item.title, { 'tone': tone, 'length': length, 'engagement_goal': engagement_goal, 'creativity_level': creativity_level, 'content': optimization.get('content', ''), 'timestamp': datetime.now() } ) else: st.error("Failed to optimize content. Please try again.") except Exception as e: logger.error(f"Error optimizing content: {str(e)}") st.error("An error occurred while optimizing content. Please try again.") with opt_tabs[1]: st.subheader("SEO Optimization") # SEO optimization content here with opt_tabs[2]: st.subheader("Content Preview") # Content preview here with opt_tabs[3]: st.subheader("Optimization History") # Optimization history here with opt_tabs[4]: st.subheader("Performance Analytics") # Analytics content here except Exception as e: logger.error(f"Error processing selected content: {str(e)}") st.error("Error processing selected content. Please try again.") # Remove everything after this point