Content Calendar, Content Gap Analysis, and Content Optimization

This commit is contained in:
ajaysi
2025-05-27 09:15:08 +05:30
parent 4049d19787
commit 889021c078
100 changed files with 18504 additions and 1251 deletions

View File

@@ -0,0 +1,185 @@
import unittest
from typing import Dict, Any
from ..models.calendar import ContentType
from ..core.ai_generator import AIContentGenerator
class TestAIContentGenerator(unittest.TestCase):
"""Test cases for AIContentGenerator."""
def setUp(self):
"""Set up test cases."""
self.generator = AIContentGenerator()
self.test_title = "10 Ways to Improve Your SEO Strategy"
self.test_content_type = ContentType.BLOG_POST
self.test_context = {
"website_url": "https://example.com",
"target_audience": "digital marketers",
"content_goals": ["educate", "generate leads"]
}
def test_generate_headings(self):
"""Test heading generation."""
headings = self.generator.generate_headings(
title=self.test_title,
content_type=self.test_content_type,
context=self.test_context
)
self.assertIsInstance(headings, list)
for heading in headings:
self.assertIn('title', heading)
self.assertIn('level', heading)
self.assertIn('keywords', heading)
self.assertIn('summary', heading)
# Verify heading level
self.assertEqual(heading['level'], 1)
# Verify heading content
self.assertIsInstance(heading['title'], str)
self.assertIsInstance(heading['keywords'], list)
self.assertIsInstance(heading['summary'], str)
def test_generate_subheadings(self):
"""Test subheading generation."""
main_heading = {
'title': 'Understanding SEO Basics',
'level': 1,
'keywords': ['SEO', 'basics', 'fundamentals'],
'summary': 'Introduction to core SEO concepts'
}
subheadings = self.generator.generate_subheadings(
main_heading=main_heading,
content_type=self.test_content_type,
context=self.test_context
)
self.assertIsInstance(subheadings, list)
for subheading in subheadings:
self.assertIn('title', subheading)
self.assertIn('level', subheading)
self.assertIn('keywords', subheading)
self.assertIn('summary', subheading)
# Verify subheading level
self.assertEqual(subheading['level'], 2)
# Verify subheading content
self.assertIsInstance(subheading['title'], str)
self.assertIsInstance(subheading['keywords'], list)
self.assertIsInstance(subheading['summary'], str)
def test_generate_key_points(self):
"""Test key points generation."""
key_points = self.generator.generate_key_points(
title=self.test_title,
content_type=self.test_content_type,
context=self.test_context
)
self.assertIsInstance(key_points, list)
for point in key_points:
self.assertIn('point', point)
self.assertIn('importance', point)
self.assertIn('supporting_evidence', point)
self.assertIn('related_keywords', point)
# Verify point content
self.assertIsInstance(point['point'], str)
self.assertIn(point['importance'], ['high', 'medium', 'low'])
self.assertIsInstance(point['supporting_evidence'], list)
self.assertIsInstance(point['related_keywords'], list)
def test_generate_content_flow(self):
"""Test content flow generation."""
outline = {
'main_headings': [
{
'title': 'Introduction',
'level': 1,
'keywords': ['SEO', 'introduction'],
'summary': 'Overview of SEO importance'
}
],
'subheadings': {
'Introduction': [
{
'title': 'What is SEO?',
'level': 2,
'keywords': ['definition', 'basics'],
'summary': 'Basic definition of SEO'
}
]
}
}
flow = self.generator.generate_content_flow(
title=self.test_title,
content_type=self.test_content_type,
outline=outline
)
self.assertIsInstance(flow, dict)
self.assertIn('introduction', flow)
self.assertIn('main_sections', flow)
self.assertIn('conclusion', flow)
self.assertIn('transitions', flow)
self.assertIn('content_pacing', flow)
# Verify flow content
self.assertIsInstance(flow['introduction'], dict)
self.assertIsInstance(flow['main_sections'], list)
self.assertIsInstance(flow['conclusion'], dict)
self.assertIsInstance(flow['transitions'], list)
self.assertIsInstance(flow['content_pacing'], dict)
def test_prompt_creation(self):
"""Test prompt creation methods."""
# Test heading prompt
heading_prompt = self.generator._create_heading_prompt(
title=self.test_title,
content_type=self.test_content_type,
gaps={'opportunities': ['keyword research', 'content optimization']}
)
self.assertIsInstance(heading_prompt, str)
self.assertIn(self.test_title, heading_prompt)
self.assertIn(self.test_content_type.value, heading_prompt)
# Test subheading prompt
main_heading = {
'title': 'Understanding SEO Basics',
'level': 1,
'keywords': ['SEO', 'basics'],
'summary': 'Introduction to SEO'
}
subheading_prompt = self.generator._create_subheading_prompt(
main_heading=main_heading,
content_type=self.test_content_type,
context=self.test_context
)
self.assertIsInstance(subheading_prompt, str)
self.assertIn(main_heading['title'], subheading_prompt)
# Test key points prompt
key_points_prompt = self.generator._create_key_points_prompt(
title=self.test_title,
content_type=self.test_content_type,
seo_data={'keywords': ['SEO', 'strategy']},
context=self.test_context
)
self.assertIsInstance(key_points_prompt, str)
self.assertIn(self.test_title, key_points_prompt)
# Test flow prompt
flow_prompt = self.generator._create_flow_prompt(
title=self.test_title,
content_type=self.test_content_type,
outline={'main_headings': []}
)
self.assertIsInstance(flow_prompt, str)
self.assertIn(self.test_title, flow_prompt)
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,132 @@
import unittest
from datetime import datetime
from typing import Dict, Any
from ..models.calendar import ContentItem, ContentType, Platform, SEOData
from ..core.content_brief import ContentBriefGenerator
class TestContentBriefGenerator(unittest.TestCase):
"""Test cases for ContentBriefGenerator."""
def setUp(self):
"""Set up test cases."""
self.generator = ContentBriefGenerator()
self.test_content_item = self._create_test_content_item()
def _create_test_content_item(self) -> ContentItem:
"""Create a test content item."""
return ContentItem(
id="test-001",
title="10 Ways to Improve Your SEO Strategy",
description="A comprehensive guide to enhancing your website's SEO performance",
content_type=ContentType.BLOG_POST,
platforms=[Platform.WEBSITE, Platform.LINKEDIN],
publish_date=datetime.now(),
seo_data=SEOData(
keywords=["SEO", "search engine optimization", "digital marketing"],
meta_description="Learn effective SEO strategies to boost your website's visibility",
structured_data={}
),
platform_specs={
"website": {
"format": "blog post",
"min_length": 1500
},
"linkedin": {
"format": "article",
"min_length": 800
}
},
context={
"website_url": "https://example.com",
"target_audience": "digital marketers",
"content_goals": ["educate", "generate leads"]
}
)
def test_generate_brief(self):
"""Test content brief generation."""
# Generate brief
brief = self.generator.generate_brief(
content_item=self.test_content_item,
target_audience={
"demographics": {
"age_range": "25-45",
"profession": "digital marketers"
},
"interests": ["SEO", "content marketing", "digital strategy"],
"pain_points": [
"low search rankings",
"poor content performance",
"lack of organic traffic"
]
}
)
# Verify brief structure
self.assertIsInstance(brief, dict)
self.assertIn('title', brief)
self.assertIn('content_type', brief)
self.assertIn('outline', brief)
self.assertIn('key_points', brief)
self.assertIn('content_flow', brief)
self.assertIn('target_audience', brief)
self.assertIn('seo_data', brief)
self.assertIn('platform_specs', brief)
# Verify outline structure
outline = brief['outline']
self.assertIn('main_headings', outline)
self.assertIn('subheadings', outline)
# Verify key points
self.assertIsInstance(brief['key_points'], list)
# Verify content flow
flow = brief['content_flow']
self.assertIn('introduction', flow)
self.assertIn('main_sections', flow)
self.assertIn('conclusion', flow)
self.assertIn('transitions', flow)
self.assertIn('content_pacing', flow)
def test_generate_brief_without_audience(self):
"""Test content brief generation without target audience data."""
brief = self.generator.generate_brief(
content_item=self.test_content_item
)
self.assertIsInstance(brief, dict)
self.assertIn('target_audience', brief)
self.assertEqual(brief['target_audience'], {})
def test_generate_outline(self):
"""Test outline generation."""
outline = self.generator._generate_outline(self.test_content_item)
self.assertIsInstance(outline, dict)
self.assertIn('main_headings', outline)
self.assertIn('subheadings', outline)
# Verify main headings
main_headings = outline['main_headings']
self.assertIsInstance(main_headings, list)
for heading in main_headings:
self.assertIn('title', heading)
self.assertIn('level', heading)
self.assertIn('keywords', heading)
self.assertIn('summary', heading)
# Verify subheadings
subheadings = outline['subheadings']
self.assertIsInstance(subheadings, dict)
for heading_title, heading_subheadings in subheadings.items():
self.assertIsInstance(heading_subheadings, list)
for subheading in heading_subheadings:
self.assertIn('title', subheading)
self.assertIn('level', subheading)
self.assertIn('keywords', subheading)
self.assertIn('summary', subheading)
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,171 @@
import unittest
from datetime import datetime, timedelta
from typing import Dict, Any
from ..integrations.integration_manager import IntegrationManager
class TestIntegrationManager(unittest.TestCase):
"""Test cases for the IntegrationManager class."""
def setUp(self):
"""Set up test fixtures."""
self.integration_manager = IntegrationManager()
self.start_date = datetime.now()
self.end_date = self.start_date + timedelta(days=30)
self.platforms = ['instagram', 'twitter', 'linkedin', 'blog', 'facebook']
self.content_types = ['article', 'social', 'video']
self.target_audience = {
'age_range': '25-34',
'interests': ['technology', 'marketing'],
'location': 'global'
}
self.industry = 'technology'
self.keywords = ['AI', 'content marketing', 'social media']
# Sample content item
self.sample_content = {
'title': 'The Future of AI in Content Marketing',
'content': 'AI is revolutionizing content marketing...',
'content_type': 'article',
'keywords': ['AI', 'content marketing', 'automation'],
'target_audience': self.target_audience,
'industry': self.industry
}
def test_create_cross_platform_calendar(self):
"""Test creating a cross-platform content calendar."""
calendar = self.integration_manager.create_cross_platform_calendar(
start_date=self.start_date,
end_date=self.end_date,
platforms=self.platforms,
content_types=self.content_types,
target_audience=self.target_audience,
industry=self.industry,
keywords=self.keywords
)
# Check basic structure
self.assertIn('base_calendar', calendar)
self.assertIn('platform_calendars', calendar)
self.assertIn('metadata', calendar)
# Check platform calendars
platform_calendars = calendar['platform_calendars']
self.assertEqual(len(platform_calendars), len(self.platforms))
for platform in self.platforms:
self.assertIn(platform, platform_calendars)
platform_calendar = platform_calendars[platform]
self.assertIn('content_items', platform_calendar)
self.assertIn('metadata', platform_calendar)
def test_adapt_calendar_for_platform(self):
"""Test adapting calendar for a specific platform."""
# Create base calendar
calendar = self.integration_manager.create_cross_platform_calendar(
start_date=self.start_date,
end_date=self.end_date,
platforms=[self.platforms[0]], # Test with just Instagram
content_types=self.content_types,
target_audience=self.target_audience,
industry=self.industry,
keywords=self.keywords
)
# Get platform calendar
platform_calendar = calendar['platform_calendars'][self.platforms[0]]
# Check structure
self.assertIn('content_items', platform_calendar)
self.assertIn('metadata', platform_calendar)
# Check content items
for item in platform_calendar['content_items']:
self.assertIn('original_item', item)
self.assertIn('adapted_content', item)
self.assertIn('platform_specifics', item)
def test_adapt_content_item(self):
"""Test adapting a content item for a platform."""
adapted_item = self.integration_manager._adapt_content_item(
item=self.sample_content,
platform='instagram'
)
# Check structure
self.assertIsNotNone(adapted_item)
self.assertIn('original_item', adapted_item)
self.assertIn('adapted_content', adapted_item)
self.assertIn('platform_specifics', adapted_item)
# Check content adaptation
adapted_content = adapted_item['adapted_content']
self.assertIn('captions', adapted_content)
self.assertIn('hashtags', adapted_content)
self.assertIn('media_suggestions', adapted_content)
def test_get_platform_suggestions(self):
"""Test getting platform-specific suggestions."""
suggestions = self.integration_manager.get_platform_suggestions(
content=self.sample_content,
platforms=self.platforms
)
# Check structure
self.assertEqual(len(suggestions), len(self.platforms))
for platform in self.platforms:
self.assertIn(platform, suggestions)
platform_suggestions = suggestions[platform]
self.assertIsInstance(platform_suggestions, dict)
def test_validate_platform_content(self):
"""Test validating content for a platform."""
validation = self.integration_manager.validate_platform_content(
content=self.sample_content,
platform='instagram'
)
# Check structure
self.assertIn('platform', validation)
self.assertIn('is_valid', validation)
self.assertIn('specifications', validation)
# Check validation result
self.assertIsInstance(validation['is_valid'], bool)
def test_optimize_cross_platform_content(self):
"""Test optimizing content for multiple platforms."""
optimized = self.integration_manager.optimize_cross_platform_content(
content=self.sample_content,
platforms=self.platforms
)
# Check structure
self.assertEqual(len(optimized), len(self.platforms))
for platform in self.platforms:
self.assertIn(platform, optimized)
platform_optimized = optimized[platform]
self.assertIsInstance(platform_optimized, dict)
def test_error_handling(self):
"""Test error handling with invalid inputs."""
# Test with invalid platform
with self.assertRaises(Exception):
self.integration_manager.validate_platform_content(
content=self.sample_content,
platform='invalid_platform'
)
# Test with invalid content
invalid_content = {'title': 'Invalid Content'}
validation = self.integration_manager.validate_platform_content(
content=invalid_content,
platform='instagram'
)
self.assertFalse(validation['is_valid'])
self.assertIn('error', validation)
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,186 @@
import unittest
from typing import Dict, Any
from datetime import datetime
from ..integrations.platform_adapters import UnifiedPlatformAdapter
class TestUnifiedPlatformAdapter(unittest.TestCase):
"""Test cases for the UnifiedPlatformAdapter."""
def setUp(self):
"""Set up test cases."""
self.adapter = UnifiedPlatformAdapter()
self.test_content = {
'title': 'Test Content',
'content': 'This is a test content for platform adaptation.',
'keywords': ['test', 'content', 'platform'],
'tone': 'professional',
'cta': 'Learn More',
'audience': 'For All',
'language': 'English',
'industry': 'technology',
'word_count': 1000
}
def test_adapt_instagram_content(self):
"""Test Instagram content adaptation."""
adapted_content = self.adapter.adapt_content(
content=self.test_content,
platform='instagram'
)
self.assertIsInstance(adapted_content, dict)
self.assertIn('captions', adapted_content)
self.assertIn('hashtags', adapted_content)
self.assertIn('media_suggestions', adapted_content)
self.assertIn('platform_specific', adapted_content)
def test_adapt_twitter_content(self):
"""Test Twitter content adaptation."""
adapted_content = self.adapter.adapt_content(
content=self.test_content,
platform='twitter'
)
self.assertIsInstance(adapted_content, dict)
self.assertIn('tweets', adapted_content)
self.assertIn('thread_structure', adapted_content)
self.assertIn('media_suggestions', adapted_content)
self.assertIn('platform_specific', adapted_content)
def test_adapt_linkedin_content(self):
"""Test LinkedIn content adaptation."""
adapted_content = self.adapter.adapt_content(
content=self.test_content,
platform='linkedin'
)
self.assertIsInstance(adapted_content, dict)
self.assertIn('post', adapted_content)
self.assertIn('engagement_optimization', adapted_content)
self.assertIn('media_suggestions', adapted_content)
self.assertIn('platform_specific', adapted_content)
def test_adapt_blog_content(self):
"""Test blog content adaptation."""
adapted_content = self.adapter.adapt_content(
content=self.test_content,
platform='blog'
)
self.assertIsInstance(adapted_content, dict)
self.assertIn('post', adapted_content)
self.assertIn('seo_optimization', adapted_content)
self.assertIn('media_suggestions', adapted_content)
self.assertIn('platform_specific', adapted_content)
def test_adapt_facebook_content(self):
"""Test Facebook content adaptation."""
adapted_content = self.adapter.adapt_content(
content=self.test_content,
platform='facebook'
)
self.assertIsInstance(adapted_content, dict)
self.assertIn('post', adapted_content)
self.assertIn('engagement_optimization', adapted_content)
self.assertIn('media_suggestions', adapted_content)
self.assertIn('platform_specific', adapted_content)
def test_validate_content(self):
"""Test content validation."""
# Test valid content
self.assertTrue(
self.adapter.validate_content(
self.test_content,
'instagram'
)
)
# Test invalid content (missing required fields)
invalid_content = {
'title': 'Test Content',
'content': 'This is a test content.'
}
self.assertFalse(
self.adapter.validate_content(
invalid_content,
'instagram'
)
)
def test_unsupported_platform(self):
"""Test handling of unsupported platform."""
with self.assertRaises(ValueError):
self.adapter.adapt_content(
content=self.test_content,
platform='unsupported_platform'
)
def test_content_adaptation_with_context(self):
"""Test content adaptation with additional context."""
context = {
'target_audience': 'professionals',
'campaign_goals': ['awareness', 'engagement'],
'brand_voice': 'authoritative'
}
adapted_content = self.adapter.adapt_content(
content=self.test_content,
platform='linkedin',
context=context
)
self.assertIsInstance(adapted_content, dict)
self.assertIn('post', adapted_content)
self.assertIn('engagement_optimization', adapted_content)
def test_error_handling(self):
"""Test error handling in content adaptation."""
# Test with invalid content structure
invalid_content = {
'title': 123, # Invalid type
'content': None # Missing required field
}
adapted_content = self.adapter.adapt_content(
content=invalid_content,
platform='blog'
)
self.assertIn('error', adapted_content)
def test_platform_specs(self):
"""Test platform specifications."""
specs = self.adapter.platform_specs
# Check Instagram specs
self.assertIn('instagram', specs)
self.assertIn('max_caption_length', specs['instagram'])
self.assertIn('max_hashtags', specs['instagram'])
self.assertIn('required_fields', specs['instagram'])
# Check Twitter specs
self.assertIn('twitter', specs)
self.assertIn('max_tweet_length', specs['twitter'])
self.assertIn('max_thread_length', specs['twitter'])
self.assertIn('required_fields', specs['twitter'])
# Check LinkedIn specs
self.assertIn('linkedin', specs)
self.assertIn('max_post_length', specs['linkedin'])
self.assertIn('required_fields', specs['linkedin'])
# Check blog specs
self.assertIn('blog', specs)
self.assertIn('min_word_count', specs['blog'])
self.assertIn('max_word_count', specs['blog'])
self.assertIn('required_fields', specs['blog'])
# Check Facebook specs
self.assertIn('facebook', specs)
self.assertIn('max_post_length', specs['facebook'])
self.assertIn('required_fields', specs['facebook'])
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,132 @@
import unittest
from datetime import datetime
from typing import Dict, Any
from ..integrations.seo_optimizer import SEOOptimizer
class TestSEOOptimizer(unittest.TestCase):
"""Test cases for the SEOOptimizer class."""
def setUp(self):
"""Set up test fixtures."""
self.seo_optimizer = SEOOptimizer()
# Sample content for testing
self.sample_content = {
'title': 'The Future of AI in Content Marketing',
'content': 'AI is revolutionizing content marketing...',
'keywords': ['AI', 'content marketing', 'automation'],
'author': 'John Doe',
'publish_date': datetime.now().isoformat(),
'description': 'An in-depth look at AI in content marketing',
'image_url': 'https://example.com/image.jpg',
'url': 'https://example.com/article'
}
# Sample calendar for testing
self.sample_calendar = {
'metadata': {
'start_date': datetime.now().isoformat(),
'end_date': datetime.now().isoformat(),
'platforms': ['blog', 'social'],
'content_types': ['article']
},
'content_items': [self.sample_content]
}
def test_optimize_content(self):
"""Test content optimization."""
optimized = self.seo_optimizer.optimize_content(
content=self.sample_content,
content_type='article',
language='English',
search_intent='Informational Intent'
)
# Check structure
self.assertIn('original_content', optimized)
self.assertIn('seo_optimized', optimized)
# Check SEO elements
seo_elements = optimized['seo_optimized']
self.assertIn('title', seo_elements)
self.assertIn('meta_description', seo_elements)
self.assertIn('structured_data', seo_elements)
self.assertIn('keywords', seo_elements)
def test_optimize_title(self):
"""Test title optimization."""
titles = self.seo_optimizer._optimize_title(
title=self.sample_content['title'],
keywords=self.sample_content['keywords'],
content_type='article',
language='English',
search_intent='Informational Intent'
)
# Check titles
self.assertIsInstance(titles, list)
self.assertTrue(len(titles) > 0)
def test_generate_meta_description(self):
"""Test meta description generation."""
descriptions = self.seo_optimizer._generate_meta_description(
keywords=self.sample_content['keywords'],
content_type='article',
language='English',
search_intent='Informational Intent'
)
# Check descriptions
self.assertIsInstance(descriptions, list)
self.assertTrue(len(descriptions) > 0)
def test_generate_structured_data(self):
"""Test structured data generation."""
structured_data = self.seo_optimizer._generate_structured_data(
content=self.sample_content,
content_type='article'
)
# Check structured data
self.assertIsNotNone(structured_data)
def test_optimize_calendar_content(self):
"""Test calendar content optimization."""
optimized_calendar = self.seo_optimizer.optimize_calendar_content(
calendar=self.sample_calendar,
content_type='article',
language='English',
search_intent='Informational Intent'
)
# Check structure
self.assertIn('metadata', optimized_calendar)
self.assertIn('content_items', optimized_calendar)
# Check content items
self.assertTrue(len(optimized_calendar['content_items']) > 0)
for item in optimized_calendar['content_items']:
self.assertIn('original_content', item)
self.assertIn('seo_optimized', item)
def test_error_handling(self):
"""Test error handling with invalid inputs."""
# Test with invalid content
invalid_content = {'title': 'Invalid Content'}
optimized = self.seo_optimizer.optimize_content(
content=invalid_content,
content_type='article'
)
self.assertIn('error', optimized)
# Test with invalid calendar
invalid_calendar = {'metadata': {}}
optimized_calendar = self.seo_optimizer.optimize_calendar_content(
calendar=invalid_calendar,
content_type='article'
)
self.assertIn('error', optimized_calendar)
if __name__ == '__main__':
unittest.main()