ALwrity LinkedIn Writer: Billing Dashboard: Compact View, Billing Overview, System Health Indicator, Cost Breakdown, Usage Trends, Usage Alerts, Comprehensive API Breakdown
This commit is contained in:
101
backend/test/debug_database_data.py
Normal file
101
backend/test/debug_database_data.py
Normal file
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Debug Database Data
|
||||
|
||||
This script checks what data is actually in the database for debugging.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
from loguru import logger
|
||||
|
||||
# Add the backend directory to the path
|
||||
backend_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
if backend_dir not in sys.path:
|
||||
sys.path.insert(0, backend_dir)
|
||||
|
||||
# Add the services directory to the path
|
||||
services_dir = os.path.join(backend_dir, "services")
|
||||
if services_dir not in sys.path:
|
||||
sys.path.insert(0, services_dir)
|
||||
|
||||
async def debug_database_data():
|
||||
"""Debug what data is in the database."""
|
||||
|
||||
try:
|
||||
logger.info("🔍 Debugging database data")
|
||||
|
||||
# Initialize database
|
||||
from services.database import init_database, get_db_session
|
||||
|
||||
try:
|
||||
init_database()
|
||||
logger.info("✅ Database initialized successfully")
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Database initialization failed: {str(e)}")
|
||||
return False
|
||||
|
||||
# Get database session
|
||||
db_session = get_db_session()
|
||||
if not db_session:
|
||||
logger.error("❌ Failed to get database session")
|
||||
return False
|
||||
|
||||
from services.content_planning_db import ContentPlanningDBService
|
||||
|
||||
db_service = ContentPlanningDBService(db_session)
|
||||
|
||||
# Check content strategies
|
||||
logger.info("📋 Checking content strategies...")
|
||||
strategies = await db_service.get_user_content_strategies(1)
|
||||
logger.info(f"Found {len(strategies)} strategies for user 1")
|
||||
|
||||
for strategy in strategies:
|
||||
logger.info(f"Strategy ID: {strategy.id}, Name: {strategy.name}")
|
||||
logger.info(f" Content Pillars: {strategy.content_pillars}")
|
||||
logger.info(f" Target Audience: {strategy.target_audience}")
|
||||
|
||||
# Check gap analyses
|
||||
logger.info("📋 Checking gap analyses...")
|
||||
gap_analyses = await db_service.get_user_content_gap_analyses(1)
|
||||
logger.info(f"Found {len(gap_analyses)} gap analyses for user 1")
|
||||
|
||||
for gap_analysis in gap_analyses:
|
||||
logger.info(f"Gap Analysis ID: {gap_analysis.id}")
|
||||
logger.info(f" Website URL: {gap_analysis.website_url}")
|
||||
logger.info(f" Analysis Results: {gap_analysis.analysis_results}")
|
||||
logger.info(f" Recommendations: {gap_analysis.recommendations}")
|
||||
logger.info(f" Opportunities: {gap_analysis.opportunities}")
|
||||
|
||||
# Check if analysis_results has content_gaps
|
||||
if gap_analysis.analysis_results:
|
||||
content_gaps = gap_analysis.analysis_results.get("content_gaps", [])
|
||||
logger.info(f" Content Gaps in analysis_results: {len(content_gaps)} items")
|
||||
for gap in content_gaps:
|
||||
logger.info(f" - {gap}")
|
||||
else:
|
||||
logger.info(" Analysis Results is None or empty")
|
||||
|
||||
db_session.close()
|
||||
logger.info("✅ Database debugging completed")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Debug failed with error: {str(e)}")
|
||||
return False
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Configure logging
|
||||
logger.remove()
|
||||
logger.add(sys.stderr, level="INFO", format="<green>{time:HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>")
|
||||
|
||||
# Run the debug
|
||||
success = asyncio.run(debug_database_data())
|
||||
|
||||
if success:
|
||||
logger.info("✅ Debug completed successfully!")
|
||||
sys.exit(0)
|
||||
else:
|
||||
logger.error("❌ Debug failed!")
|
||||
sys.exit(1)
|
||||
175
backend/test/debug_step8.py
Normal file
175
backend/test/debug_step8.py
Normal file
@@ -0,0 +1,175 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Debug script for Step 8 (Daily Content Planning) to isolate data type issues.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Add the project root to the Python path
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.steps.phase3.step8_daily_content_planning.daily_schedule_generator import DailyScheduleGenerator
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s | %(levelname)-8s | %(name)s:%(funcName)s:%(lineno)d - %(message)s',
|
||||
datefmt='%H:%M:%S'
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
async def debug_step8():
|
||||
"""Debug Step 8 with controlled test data."""
|
||||
|
||||
logger.info("🔍 Starting Step 8 Debug Session")
|
||||
|
||||
# Create test data with known types
|
||||
test_weekly_themes = [
|
||||
{
|
||||
"title": "Week 1 Theme: AI Implementation",
|
||||
"description": "Focus on AI tools and implementation",
|
||||
"primary_pillar": "AI and Machine Learning",
|
||||
"content_angles": ["AI tools", "Implementation guide", "Best practices"],
|
||||
"target_platforms": ["LinkedIn", "Blog", "Twitter"],
|
||||
"strategic_alignment": "High alignment with business goals",
|
||||
"gap_addressal": "Addresses AI implementation gap",
|
||||
"priority": "high",
|
||||
"estimated_impact": "High",
|
||||
"ai_confidence": 0.9,
|
||||
"week_number": 1
|
||||
},
|
||||
{
|
||||
"title": "Week 2 Theme: Digital Transformation",
|
||||
"description": "Digital transformation strategies",
|
||||
"primary_pillar": "Digital Transformation",
|
||||
"content_angles": ["Strategy", "Case studies", "ROI"],
|
||||
"target_platforms": ["LinkedIn", "Blog", "YouTube"],
|
||||
"strategic_alignment": "Medium alignment with business goals",
|
||||
"gap_addressal": "Addresses transformation gap",
|
||||
"priority": "medium",
|
||||
"estimated_impact": "Medium",
|
||||
"ai_confidence": 0.8,
|
||||
"week_number": 2
|
||||
}
|
||||
]
|
||||
|
||||
test_platform_strategies = {
|
||||
"LinkedIn": {
|
||||
"content_type": "professional",
|
||||
"posting_frequency": "daily",
|
||||
"engagement_strategy": "thought_leadership"
|
||||
},
|
||||
"Blog": {
|
||||
"content_type": "educational",
|
||||
"posting_frequency": "weekly",
|
||||
"engagement_strategy": "seo_optimized"
|
||||
},
|
||||
"Twitter": {
|
||||
"content_type": "conversational",
|
||||
"posting_frequency": "daily",
|
||||
"engagement_strategy": "community_building"
|
||||
}
|
||||
}
|
||||
|
||||
test_content_pillars = [
|
||||
{
|
||||
"name": "AI and Machine Learning",
|
||||
"weight": 0.4,
|
||||
"description": "AI tools and implementation"
|
||||
},
|
||||
{
|
||||
"name": "Digital Transformation",
|
||||
"weight": 0.3,
|
||||
"description": "Digital strategy and transformation"
|
||||
},
|
||||
{
|
||||
"name": "Business Strategy",
|
||||
"weight": 0.3,
|
||||
"description": "Strategic business insights"
|
||||
}
|
||||
]
|
||||
|
||||
test_calendar_framework = {
|
||||
"type": "monthly",
|
||||
"total_weeks": 4,
|
||||
"posting_frequency": "daily",
|
||||
"posting_days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
|
||||
"industry": "technology",
|
||||
"business_size": "sme"
|
||||
}
|
||||
|
||||
test_posting_preferences = {
|
||||
"preferred_times": ["09:00", "12:00", "15:00"],
|
||||
"posting_frequency": "daily",
|
||||
"content_count_per_day": 2
|
||||
}
|
||||
|
||||
test_business_goals = [
|
||||
"Increase brand awareness by 40%",
|
||||
"Generate 500 qualified leads per month",
|
||||
"Establish thought leadership"
|
||||
]
|
||||
|
||||
test_target_audience = {
|
||||
"primary": "Tech professionals",
|
||||
"secondary": "Business leaders",
|
||||
"demographics": {
|
||||
"age_range": "25-45",
|
||||
"location": "Global"
|
||||
}
|
||||
}
|
||||
|
||||
# Test data type validation
|
||||
logger.info("🔍 Validating test data types:")
|
||||
logger.info(f" weekly_themes: {type(test_weekly_themes)} (length: {len(test_weekly_themes)})")
|
||||
logger.info(f" platform_strategies: {type(test_platform_strategies)}")
|
||||
logger.info(f" content_pillars: {type(test_content_pillars)}")
|
||||
logger.info(f" calendar_framework: {type(test_calendar_framework)}")
|
||||
logger.info(f" posting_preferences: {type(test_posting_preferences)}")
|
||||
logger.info(f" business_goals: {type(test_business_goals)}")
|
||||
logger.info(f" target_audience: {type(test_target_audience)}")
|
||||
|
||||
# Validate weekly themes structure
|
||||
for i, theme in enumerate(test_weekly_themes):
|
||||
logger.info(f" Theme {i+1}: {type(theme)} - keys: {list(theme.keys())}")
|
||||
if not isinstance(theme, dict):
|
||||
logger.error(f"❌ Theme {i+1} is not a dictionary: {type(theme)}")
|
||||
return
|
||||
|
||||
try:
|
||||
# Initialize the daily schedule generator
|
||||
generator = DailyScheduleGenerator()
|
||||
logger.info("✅ DailyScheduleGenerator initialized successfully")
|
||||
|
||||
# Test the generate_daily_schedules method
|
||||
logger.info("🚀 Testing generate_daily_schedules method...")
|
||||
|
||||
daily_schedules = await generator.generate_daily_schedules(
|
||||
weekly_themes=test_weekly_themes,
|
||||
platform_strategies=test_platform_strategies,
|
||||
business_goals=test_business_goals,
|
||||
target_audience=test_target_audience,
|
||||
posting_preferences=test_posting_preferences,
|
||||
calendar_duration=28 # 4 weeks * 7 days
|
||||
)
|
||||
|
||||
logger.info(f"✅ Successfully generated {len(daily_schedules)} daily schedules")
|
||||
|
||||
# Log first few schedules for inspection
|
||||
for i, schedule in enumerate(daily_schedules[:3]):
|
||||
logger.info(f" Schedule {i+1}: {type(schedule)} - keys: {list(schedule.keys())}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Error in Step 8 debug: {str(e)}")
|
||||
logger.error(f"📋 Error type: {type(e)}")
|
||||
import traceback
|
||||
logger.error(f"📋 Traceback: {traceback.format_exc()}")
|
||||
return
|
||||
|
||||
logger.info("🎉 Step 8 debug completed successfully!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(debug_step8())
|
||||
118
backend/test/debug_step8_ai_response.py
Normal file
118
backend/test/debug_step8_ai_response.py
Normal file
@@ -0,0 +1,118 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Debug script to test AI response parsing in Step 8.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Add the project root to the Python path
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.steps.phase3.step8_daily_content_planning.daily_schedule_generator import DailyScheduleGenerator
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s | %(levelname)-8s | %(name)s:%(funcName)s:%(lineno)d - %(message)s',
|
||||
datefmt='%H:%M:%S'
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
async def debug_ai_response_parsing():
|
||||
"""Debug AI response parsing in Step 8."""
|
||||
|
||||
logger.info("🔍 Starting AI Response Parsing Debug")
|
||||
|
||||
# Create test data
|
||||
test_posting_day = {
|
||||
"day_number": 1,
|
||||
"date": "2025-09-01",
|
||||
"day_name": "monday",
|
||||
"posting_times": ["09:00", "12:00"],
|
||||
"content_count": 2,
|
||||
"week_number": 1
|
||||
}
|
||||
|
||||
test_weekly_theme = {
|
||||
"title": "Week 1 Theme: AI Implementation",
|
||||
"description": "Focus on AI tools and implementation",
|
||||
"content_angles": ["AI tools", "Implementation guide", "Best practices"]
|
||||
}
|
||||
|
||||
test_platform_strategies = {
|
||||
"LinkedIn": {"approach": "professional"},
|
||||
"Blog": {"approach": "educational"}
|
||||
}
|
||||
|
||||
# Test different AI response formats
|
||||
test_responses = [
|
||||
# Format 1: List of recommendations (correct format)
|
||||
[
|
||||
{
|
||||
"type": "Content Creation Opportunity",
|
||||
"title": "AI Implementation Guide",
|
||||
"description": "A comprehensive guide to AI implementation"
|
||||
},
|
||||
{
|
||||
"type": "Content Creation Opportunity",
|
||||
"title": "AI Tools Overview",
|
||||
"description": "Overview of AI tools for business"
|
||||
}
|
||||
],
|
||||
|
||||
# Format 2: Dictionary with recommendations key
|
||||
{
|
||||
"recommendations": [
|
||||
{
|
||||
"type": "Content Creation Opportunity",
|
||||
"title": "AI Implementation Guide",
|
||||
"description": "A comprehensive guide to AI implementation"
|
||||
},
|
||||
{
|
||||
"type": "Content Creation Opportunity",
|
||||
"title": "AI Tools Overview",
|
||||
"description": "Overview of AI tools for business"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
# Format 3: Float (the problematic case)
|
||||
0.95,
|
||||
|
||||
# Format 4: String
|
||||
"AI Implementation Guide",
|
||||
|
||||
# Format 5: None
|
||||
None
|
||||
]
|
||||
|
||||
generator = DailyScheduleGenerator()
|
||||
|
||||
for i, test_response in enumerate(test_responses):
|
||||
logger.info(f"🔍 Testing AI response format {i+1}: {type(test_response)} = {test_response}")
|
||||
|
||||
try:
|
||||
content_pieces = generator._parse_content_response(
|
||||
ai_response=test_response,
|
||||
posting_day=test_posting_day,
|
||||
weekly_theme=test_weekly_theme,
|
||||
platform_strategies=test_platform_strategies
|
||||
)
|
||||
|
||||
logger.info(f"✅ Format {i+1} parsed successfully: {len(content_pieces)} content pieces")
|
||||
for j, piece in enumerate(content_pieces):
|
||||
logger.info(f" Piece {j+1}: {piece.get('title', 'No title')}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Format {i+1} failed: {str(e)}")
|
||||
logger.error(f"📋 Error type: {type(e)}")
|
||||
import traceback
|
||||
logger.error(f"📋 Traceback: {traceback.format_exc()}")
|
||||
|
||||
logger.info("🎉 AI Response Parsing Debug completed!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(debug_ai_response_parsing())
|
||||
402
backend/test/debug_step8_isolated.py
Normal file
402
backend/test/debug_step8_isolated.py
Normal file
@@ -0,0 +1,402 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Step 8 Debug Script - Isolated Testing
|
||||
=====================================
|
||||
|
||||
This script tests Step 8 (Daily Content Planning) in isolation with controlled inputs
|
||||
to identify which specific parameter is causing the 'float' object has no attribute 'get' error.
|
||||
|
||||
The script will:
|
||||
1. Set up Step 8 with fixed, known dictionary inputs
|
||||
2. Test the daily content generation in isolation
|
||||
3. Identify which specific parameter is coming through as a float
|
||||
4. Help pinpoint whether the issue is in weekly_theme, posting_day, platform_strategies, or other data
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
import logging
|
||||
from typing import Dict, List, Any
|
||||
|
||||
# Add the project root to the path
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Import Step 8 components
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.steps.phase3.step8_daily_content_planning.step8_main import DailyContentPlanningStep
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.steps.phase3.step8_daily_content_planning.daily_schedule_generator import DailyScheduleGenerator
|
||||
|
||||
def create_controlled_test_data():
|
||||
"""Create controlled test data with known types for Step 8 testing."""
|
||||
|
||||
# 1. Weekly themes from Step 7 (should be list of dictionaries)
|
||||
weekly_themes = [
|
||||
{
|
||||
"title": "Week 1 Theme: AI Implementation Guide",
|
||||
"description": "Comprehensive guide on AI implementation for businesses",
|
||||
"primary_pillar": "AI and Machine Learning",
|
||||
"secondary_pillars": ["Digital Transformation", "Innovation"],
|
||||
"strategic_alignment": "high",
|
||||
"audience_alignment": "high",
|
||||
"week_number": 1,
|
||||
"content_count": 5,
|
||||
"priority": "high",
|
||||
"estimated_impact": "High",
|
||||
"ai_confidence": 0.9
|
||||
},
|
||||
{
|
||||
"title": "Week 2 Theme: Digital Transformation Strategies",
|
||||
"description": "Strategic approaches to digital transformation",
|
||||
"primary_pillar": "Digital Transformation",
|
||||
"secondary_pillars": ["Business Strategy", "Innovation"],
|
||||
"strategic_alignment": "high",
|
||||
"audience_alignment": "medium",
|
||||
"week_number": 2,
|
||||
"content_count": 4,
|
||||
"priority": "medium",
|
||||
"estimated_impact": "Medium",
|
||||
"ai_confidence": 0.8
|
||||
}
|
||||
]
|
||||
|
||||
# 2. Platform strategies from Step 6 (should be dictionary)
|
||||
platform_strategies = {
|
||||
"linkedin": {
|
||||
"content_types": ["articles", "posts", "videos"],
|
||||
"posting_times": ["09:00", "12:00", "15:00"],
|
||||
"content_adaptation": "professional tone, industry insights",
|
||||
"engagement_strategy": "thought leadership content"
|
||||
},
|
||||
"twitter": {
|
||||
"content_types": ["tweets", "threads", "images"],
|
||||
"posting_times": ["08:00", "11:00", "14:00", "17:00"],
|
||||
"content_adaptation": "concise, engaging, hashtag optimization",
|
||||
"engagement_strategy": "conversation starters"
|
||||
}
|
||||
}
|
||||
|
||||
# 3. Content pillars from Step 5 (should be list)
|
||||
content_pillars = [
|
||||
"AI and Machine Learning",
|
||||
"Digital Transformation",
|
||||
"Innovation and Technology Trends",
|
||||
"Business Strategy and Growth"
|
||||
]
|
||||
|
||||
# 4. Calendar framework from Step 4 (should be dictionary)
|
||||
calendar_framework = {
|
||||
"duration_weeks": 4,
|
||||
"content_frequency": "daily",
|
||||
"posting_schedule": {
|
||||
"monday": ["09:00", "12:00", "15:00"],
|
||||
"tuesday": ["09:00", "12:00", "15:00"],
|
||||
"wednesday": ["09:00", "12:00", "15:00"],
|
||||
"thursday": ["09:00", "12:00", "15:00"],
|
||||
"friday": ["09:00", "12:00", "15:00"]
|
||||
},
|
||||
"theme_structure": "weekly_themes",
|
||||
"content_mix": {
|
||||
"blog_posts": 0.4,
|
||||
"social_media": 0.3,
|
||||
"videos": 0.2,
|
||||
"infographics": 0.1
|
||||
}
|
||||
}
|
||||
|
||||
# 5. Business goals from Step 1 (should be list)
|
||||
business_goals = [
|
||||
"Increase brand awareness by 40%",
|
||||
"Generate 500 qualified leads per month",
|
||||
"Establish thought leadership"
|
||||
]
|
||||
|
||||
# 6. Target audience from Step 1 (should be dictionary)
|
||||
target_audience = {
|
||||
"primary": "Tech professionals",
|
||||
"secondary": "Business leaders",
|
||||
"demographics": {
|
||||
"age_range": "25-45",
|
||||
"location": "Global",
|
||||
"interests": ["technology", "innovation", "business growth"]
|
||||
}
|
||||
}
|
||||
|
||||
# 7. Keywords from Step 2 (should be list)
|
||||
keywords = [
|
||||
"AI implementation",
|
||||
"digital transformation",
|
||||
"machine learning",
|
||||
"business automation",
|
||||
"technology trends"
|
||||
]
|
||||
|
||||
return {
|
||||
"weekly_themes": weekly_themes,
|
||||
"platform_strategies": platform_strategies,
|
||||
"content_pillars": content_pillars,
|
||||
"calendar_framework": calendar_framework,
|
||||
"business_goals": business_goals,
|
||||
"target_audience": target_audience,
|
||||
"keywords": keywords
|
||||
}
|
||||
|
||||
def validate_data_types(data: Dict[str, Any], test_name: str):
|
||||
"""Validate that all data has the expected types."""
|
||||
logger.info(f"🔍 Validating data types for {test_name}")
|
||||
|
||||
expected_types = {
|
||||
"weekly_themes": list,
|
||||
"platform_strategies": dict,
|
||||
"content_pillars": list,
|
||||
"calendar_framework": dict,
|
||||
"business_goals": list,
|
||||
"target_audience": dict,
|
||||
"keywords": list
|
||||
}
|
||||
|
||||
for key, expected_type in expected_types.items():
|
||||
if key in data:
|
||||
actual_type = type(data[key])
|
||||
if actual_type != expected_type:
|
||||
logger.error(f"❌ Type mismatch for {key}: expected {expected_type.__name__}, got {actual_type.__name__}")
|
||||
logger.error(f" Value: {data[key]}")
|
||||
return False
|
||||
else:
|
||||
logger.info(f"✅ {key}: {actual_type.__name__} (correct)")
|
||||
else:
|
||||
logger.warning(f"⚠️ Missing key: {key}")
|
||||
|
||||
return True
|
||||
|
||||
async def test_daily_schedule_generator_isolated():
|
||||
"""Test the DailyScheduleGenerator in isolation with controlled inputs."""
|
||||
logger.info("🧪 Testing DailyScheduleGenerator in isolation")
|
||||
|
||||
# Create controlled test data
|
||||
test_data = create_controlled_test_data()
|
||||
|
||||
# Validate data types
|
||||
if not validate_data_types(test_data, "DailyScheduleGenerator"):
|
||||
logger.error("❌ Data type validation failed")
|
||||
return False
|
||||
|
||||
try:
|
||||
# Create DailyScheduleGenerator instance
|
||||
generator = DailyScheduleGenerator()
|
||||
|
||||
# Test the generate_daily_schedules method
|
||||
logger.info("📅 Testing generate_daily_schedules method")
|
||||
|
||||
# Get posting preferences and calendar duration
|
||||
posting_preferences = {
|
||||
"preferred_times": ["09:00", "12:00", "15:00"],
|
||||
"posting_frequency": "daily"
|
||||
}
|
||||
calendar_duration = test_data["calendar_framework"]["duration_weeks"] * 7
|
||||
|
||||
# Call the method with controlled inputs
|
||||
daily_schedules = await generator.generate_daily_schedules(
|
||||
test_data["weekly_themes"],
|
||||
test_data["platform_strategies"],
|
||||
test_data["content_pillars"],
|
||||
test_data["calendar_framework"],
|
||||
posting_preferences,
|
||||
calendar_duration
|
||||
)
|
||||
|
||||
logger.info(f"✅ DailyScheduleGenerator test successful")
|
||||
logger.info(f" Generated {len(daily_schedules)} daily schedules")
|
||||
|
||||
# Validate the output
|
||||
if isinstance(daily_schedules, list):
|
||||
logger.info("✅ Output is a list (correct)")
|
||||
for i, schedule in enumerate(daily_schedules[:3]): # Show first 3
|
||||
logger.info(f" Schedule {i+1}: {type(schedule)} - {schedule.get('day_number', 'N/A')}")
|
||||
else:
|
||||
logger.error(f"❌ Output is not a list: {type(daily_schedules)}")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ DailyScheduleGenerator test failed: {str(e)}")
|
||||
logger.error(f" Exception type: {type(e).__name__}")
|
||||
import traceback
|
||||
logger.error(f" Traceback: {traceback.format_exc()}")
|
||||
return False
|
||||
|
||||
async def test_step8_execute_method():
|
||||
"""Test Step 8's execute method with controlled inputs."""
|
||||
logger.info("🧪 Testing Step 8 execute method")
|
||||
|
||||
# Create controlled test data
|
||||
test_data = create_controlled_test_data()
|
||||
|
||||
# Validate data types
|
||||
if not validate_data_types(test_data, "Step 8 Execute"):
|
||||
logger.error("❌ Data type validation failed")
|
||||
return False
|
||||
|
||||
try:
|
||||
# Create Step 8 instance
|
||||
step8 = DailyContentPlanningStep()
|
||||
|
||||
# Create context with controlled data
|
||||
context = {
|
||||
"step_results": {
|
||||
"step_07": {
|
||||
"result": {
|
||||
"weekly_themes": test_data["weekly_themes"]
|
||||
}
|
||||
},
|
||||
"step_06": {
|
||||
"result": {
|
||||
"platform_strategies": test_data["platform_strategies"]
|
||||
}
|
||||
},
|
||||
"step_05": {
|
||||
"result": {
|
||||
"content_pillars": test_data["content_pillars"]
|
||||
}
|
||||
},
|
||||
"step_04": {
|
||||
"result": {
|
||||
"calendar_framework": test_data["calendar_framework"]
|
||||
}
|
||||
},
|
||||
"step_01": {
|
||||
"result": {
|
||||
"business_goals": test_data["business_goals"],
|
||||
"target_audience": test_data["target_audience"]
|
||||
}
|
||||
},
|
||||
"step_02": {
|
||||
"result": {
|
||||
"keywords": test_data["keywords"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"user_data": {
|
||||
"business_goals": test_data["business_goals"],
|
||||
"target_audience": test_data["target_audience"],
|
||||
"keywords": test_data["keywords"]
|
||||
}
|
||||
}
|
||||
|
||||
# Test the execute method
|
||||
logger.info("📅 Testing Step 8 execute method")
|
||||
result = await step8.execute(context)
|
||||
|
||||
logger.info(f"✅ Step 8 execute test successful")
|
||||
logger.info(f" Result type: {type(result)}")
|
||||
logger.info(f" Result keys: {list(result.keys()) if isinstance(result, dict) else 'N/A'}")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Step 8 execute test failed: {str(e)}")
|
||||
logger.error(f" Exception type: {type(e).__name__}")
|
||||
import traceback
|
||||
logger.error(f" Traceback: {traceback.format_exc()}")
|
||||
return False
|
||||
|
||||
async def test_specific_methods_with_debugging():
|
||||
"""Test specific methods with detailed debugging to identify the float issue."""
|
||||
logger.info("🔍 Testing specific methods with detailed debugging")
|
||||
|
||||
# Create controlled test data
|
||||
test_data = create_controlled_test_data()
|
||||
|
||||
try:
|
||||
# Create DailyScheduleGenerator instance
|
||||
generator = DailyScheduleGenerator()
|
||||
|
||||
# Test _get_weekly_theme method specifically
|
||||
logger.info("🔍 Testing _get_weekly_theme method")
|
||||
for week_num in [1, 2]:
|
||||
theme = generator._get_weekly_theme(test_data["weekly_themes"], week_num)
|
||||
logger.info(f" Week {week_num} theme type: {type(theme)}")
|
||||
logger.info(f" Week {week_num} theme: {theme}")
|
||||
|
||||
if not isinstance(theme, dict):
|
||||
logger.error(f"❌ Week {week_num} theme is not a dictionary!")
|
||||
return False
|
||||
|
||||
# Test _generate_daily_content method with controlled inputs
|
||||
logger.info("🔍 Testing _generate_daily_content method")
|
||||
|
||||
# Create a controlled posting_day
|
||||
posting_day = {
|
||||
"day_number": 1,
|
||||
"week_number": 1,
|
||||
"content_count": 3,
|
||||
"platforms": ["linkedin", "twitter"]
|
||||
}
|
||||
|
||||
# Test with controlled weekly theme
|
||||
weekly_theme = test_data["weekly_themes"][0] # First theme
|
||||
|
||||
# Test the method
|
||||
content = await generator._generate_daily_content(
|
||||
posting_day,
|
||||
weekly_theme,
|
||||
test_data["platform_strategies"],
|
||||
test_data["content_pillars"],
|
||||
test_data["calendar_framework"]
|
||||
)
|
||||
|
||||
logger.info(f"✅ _generate_daily_content test successful")
|
||||
logger.info(f" Content type: {type(content)}")
|
||||
logger.info(f" Content: {content}")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Specific method test failed: {str(e)}")
|
||||
logger.error(f" Exception type: {type(e).__name__}")
|
||||
import traceback
|
||||
logger.error(f" Traceback: {traceback.format_exc()}")
|
||||
return False
|
||||
|
||||
async def main():
|
||||
"""Main debug function."""
|
||||
logger.info("🚀 Starting Step 8 Debug Script")
|
||||
logger.info("=" * 50)
|
||||
|
||||
# Test 1: DailyScheduleGenerator in isolation
|
||||
logger.info("\n🧪 Test 1: DailyScheduleGenerator in isolation")
|
||||
success1 = await test_daily_schedule_generator_isolated()
|
||||
|
||||
# Test 2: Step 8 execute method
|
||||
logger.info("\n🧪 Test 2: Step 8 execute method")
|
||||
success2 = await test_step8_execute_method()
|
||||
|
||||
# Test 3: Specific methods with debugging
|
||||
logger.info("\n🧪 Test 3: Specific methods with debugging")
|
||||
success3 = await test_specific_methods_with_debugging()
|
||||
|
||||
# Summary
|
||||
logger.info("\n" + "=" * 50)
|
||||
logger.info("📊 Debug Results Summary")
|
||||
logger.info("=" * 50)
|
||||
logger.info(f"✅ Test 1 (DailyScheduleGenerator): {'PASSED' if success1 else 'FAILED'}")
|
||||
logger.info(f"✅ Test 2 (Step 8 Execute): {'PASSED' if success2 else 'FAILED'}")
|
||||
logger.info(f"✅ Test 3 (Specific Methods): {'PASSED' if success3 else 'FAILED'}")
|
||||
|
||||
if success1 and success2 and success3:
|
||||
logger.info("🎉 All tests passed! Step 8 is working correctly with controlled inputs.")
|
||||
logger.info("💡 The issue might be in the data flow from previous steps.")
|
||||
else:
|
||||
logger.error("❌ Some tests failed. Check the logs above for specific issues.")
|
||||
|
||||
logger.info("=" * 50)
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
197
backend/test/deploy_persona_system.py
Normal file
197
backend/test/deploy_persona_system.py
Normal file
@@ -0,0 +1,197 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Deployment script for the Persona System.
|
||||
Sets up database tables and validates the complete system.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Add the backend directory to the Python path
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
from loguru import logger
|
||||
|
||||
def deploy_persona_system():
|
||||
"""Deploy the complete persona system."""
|
||||
|
||||
logger.info("🚀 Deploying Persona System")
|
||||
|
||||
try:
|
||||
# Step 1: Create database tables
|
||||
logger.info("📊 Step 1: Creating database tables...")
|
||||
from scripts.create_persona_tables import create_persona_tables
|
||||
create_persona_tables()
|
||||
logger.info("✅ Database tables created")
|
||||
|
||||
# Step 2: Validate Gemini integration
|
||||
logger.info("🤖 Step 2: Validating Gemini integration...")
|
||||
from services.llm_providers.gemini_provider import gemini_structured_json_response
|
||||
|
||||
test_schema = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {"type": "string"},
|
||||
"timestamp": {"type": "string"}
|
||||
},
|
||||
"required": ["status"]
|
||||
}
|
||||
|
||||
test_response = gemini_structured_json_response(
|
||||
prompt="Return status='ready' and current timestamp",
|
||||
schema=test_schema,
|
||||
temperature=0.1,
|
||||
max_tokens=1024
|
||||
)
|
||||
|
||||
if "error" in test_response:
|
||||
logger.warning(f"⚠️ Gemini test warning: {test_response['error']}")
|
||||
else:
|
||||
logger.info("✅ Gemini integration validated")
|
||||
|
||||
# Step 3: Test persona service
|
||||
logger.info("🧠 Step 3: Testing persona service...")
|
||||
from services.persona_analysis_service import PersonaAnalysisService
|
||||
persona_service = PersonaAnalysisService()
|
||||
logger.info("✅ Persona service initialized")
|
||||
|
||||
# Step 4: Test replication engine
|
||||
logger.info("⚙️ Step 4: Testing replication engine...")
|
||||
from services.persona_replication_engine import PersonaReplicationEngine
|
||||
replication_engine = PersonaReplicationEngine()
|
||||
logger.info("✅ Replication engine initialized")
|
||||
|
||||
# Step 5: Validate API endpoints
|
||||
logger.info("🌐 Step 5: Validating API endpoints...")
|
||||
from api.persona_routes import router
|
||||
logger.info(f"✅ Persona router configured with {len(router.routes)} routes")
|
||||
|
||||
logger.info("🎉 Persona System deployed successfully!")
|
||||
|
||||
# Print deployment summary
|
||||
print_deployment_summary()
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Deployment failed: {str(e)}")
|
||||
return False
|
||||
|
||||
def print_deployment_summary():
|
||||
"""Print deployment summary and next steps."""
|
||||
|
||||
logger.info("📋 PERSONA SYSTEM DEPLOYMENT SUMMARY")
|
||||
logger.info("=" * 50)
|
||||
|
||||
logger.info("✅ Database Tables:")
|
||||
logger.info(" - writing_personas")
|
||||
logger.info(" - platform_personas")
|
||||
logger.info(" - persona_analysis_results")
|
||||
logger.info(" - persona_validation_results")
|
||||
|
||||
logger.info("✅ Services:")
|
||||
logger.info(" - PersonaAnalysisService")
|
||||
logger.info(" - PersonaReplicationEngine")
|
||||
|
||||
logger.info("✅ API Endpoints:")
|
||||
logger.info(" - POST /api/personas/generate")
|
||||
logger.info(" - GET /api/personas/user/{user_id}")
|
||||
logger.info(" - GET /api/personas/platform/{platform}")
|
||||
logger.info(" - GET /api/personas/export/{platform}")
|
||||
|
||||
logger.info("✅ Platform Support:")
|
||||
logger.info(" - Twitter/X, LinkedIn, Instagram, Facebook")
|
||||
logger.info(" - Blog, Medium, Substack")
|
||||
|
||||
logger.info("🔧 NEXT STEPS:")
|
||||
logger.info("1. Complete onboarding with website analysis (Step 2)")
|
||||
logger.info("2. Set research preferences (Step 3)")
|
||||
logger.info("3. Generate persona in Final Step (Step 6)")
|
||||
logger.info("4. Export hardened prompts for external AI systems")
|
||||
logger.info("5. Use persona for consistent content generation")
|
||||
|
||||
logger.info("=" * 50)
|
||||
|
||||
def validate_deployment():
|
||||
"""Validate that all components are working correctly."""
|
||||
|
||||
logger.info("🔍 Validating deployment...")
|
||||
|
||||
validation_results = {
|
||||
"database": False,
|
||||
"gemini": False,
|
||||
"persona_service": False,
|
||||
"replication_engine": False,
|
||||
"api_routes": False
|
||||
}
|
||||
|
||||
try:
|
||||
# Test database
|
||||
from services.database import get_db_session
|
||||
session = get_db_session()
|
||||
if session:
|
||||
session.close()
|
||||
validation_results["database"] = True
|
||||
logger.info("✅ Database connection validated")
|
||||
|
||||
# Test Gemini
|
||||
from services.llm_providers.gemini_provider import get_gemini_api_key
|
||||
api_key = get_gemini_api_key()
|
||||
if api_key and api_key != "your_gemini_api_key_here":
|
||||
validation_results["gemini"] = True
|
||||
logger.info("✅ Gemini API key configured")
|
||||
else:
|
||||
logger.warning("⚠️ Gemini API key not configured")
|
||||
|
||||
# Test services
|
||||
from services.persona_analysis_service import PersonaAnalysisService
|
||||
from services.persona_replication_engine import PersonaReplicationEngine
|
||||
|
||||
PersonaAnalysisService()
|
||||
PersonaReplicationEngine()
|
||||
validation_results["persona_service"] = True
|
||||
validation_results["replication_engine"] = True
|
||||
logger.info("✅ Services validated")
|
||||
|
||||
# Test API routes
|
||||
from api.persona_routes import router
|
||||
if len(router.routes) > 0:
|
||||
validation_results["api_routes"] = True
|
||||
logger.info("✅ API routes validated")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Validation error: {str(e)}")
|
||||
|
||||
# Summary
|
||||
passed = sum(validation_results.values())
|
||||
total = len(validation_results)
|
||||
|
||||
logger.info(f"📊 Validation Results: {passed}/{total} components validated")
|
||||
|
||||
if passed == total:
|
||||
logger.info("🎉 All components validated successfully!")
|
||||
return True
|
||||
else:
|
||||
logger.warning("⚠️ Some components failed validation")
|
||||
for component, status in validation_results.items():
|
||||
status_icon = "✅" if status else "❌"
|
||||
logger.info(f" {status_icon} {component}")
|
||||
return False
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Deploy system
|
||||
deployment_success = deploy_persona_system()
|
||||
|
||||
if deployment_success:
|
||||
# Validate deployment
|
||||
validation_success = validate_deployment()
|
||||
|
||||
if validation_success:
|
||||
logger.info("🎉 Persona System ready for production!")
|
||||
sys.exit(0)
|
||||
else:
|
||||
logger.error("❌ Deployment validation failed")
|
||||
sys.exit(1)
|
||||
else:
|
||||
logger.error("❌ Deployment failed")
|
||||
sys.exit(1)
|
||||
48
backend/test/fix_imports.py
Normal file
48
backend/test/fix_imports.py
Normal file
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Script to fix import paths in step files
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
def fix_imports_in_file(file_path):
|
||||
"""Fix import paths in a file."""
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
# Fix the base_step import path
|
||||
# Change from ..base_step to ...base_step for subdirectories
|
||||
if '/step9_content_recommendations/' in file_path or '/step10_performance_optimization/' in file_path or '/step11_strategy_alignment_validation/' in file_path or '/step12_final_calendar_assembly/' in file_path:
|
||||
content = re.sub(r'from \.\.base_step import', 'from ...base_step import', content)
|
||||
|
||||
with open(file_path, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
|
||||
print(f"✅ Fixed imports in {file_path}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"❌ Error fixing {file_path}: {e}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
"""Main function to fix all import paths."""
|
||||
base_path = "services/calendar_generation_datasource_framework/prompt_chaining/steps"
|
||||
|
||||
# Files that need fixing
|
||||
files_to_fix = [
|
||||
f"{base_path}/phase3/step9_content_recommendations/step9_main.py",
|
||||
f"{base_path}/phase4/step10_performance_optimization/step10_main.py",
|
||||
f"{base_path}/phase4/step11_strategy_alignment_validation/step11_main.py",
|
||||
f"{base_path}/phase4/step12_final_calendar_assembly/step12_main.py",
|
||||
]
|
||||
|
||||
for file_path in files_to_fix:
|
||||
if os.path.exists(file_path):
|
||||
fix_imports_in_file(file_path)
|
||||
else:
|
||||
print(f"⚠️ File not found: {file_path}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
66
backend/test/test_calendar_generation.py
Normal file
66
backend/test/test_calendar_generation.py
Normal file
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test script for calendar generation API
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import aiohttp
|
||||
import json
|
||||
|
||||
async def test_calendar_generation():
|
||||
"""Test the calendar generation API."""
|
||||
|
||||
url = "http://localhost:8000/api/content-planning/calendar-generation/start"
|
||||
|
||||
payload = {
|
||||
"user_id": 1,
|
||||
"strategy_id": 1,
|
||||
"calendar_type": "monthly",
|
||||
"industry": "technology",
|
||||
"business_size": "sme"
|
||||
}
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
try:
|
||||
async with session.post(url, json=payload) as response:
|
||||
if response.status == 200:
|
||||
result = await response.json()
|
||||
print("✅ Calendar generation started successfully!")
|
||||
print(f"Session ID: {result.get('session_id')}")
|
||||
|
||||
# Test progress endpoint
|
||||
session_id = result.get('session_id')
|
||||
if session_id:
|
||||
print(f"\n🔄 Testing progress for session: {session_id}")
|
||||
progress_url = f"http://localhost:8000/api/content-planning/calendar-generation/progress/{session_id}"
|
||||
|
||||
async with session.get(progress_url) as progress_response:
|
||||
if progress_response.status == 200:
|
||||
progress_data = await progress_response.json()
|
||||
print("✅ Progress endpoint working!")
|
||||
print(f"Status: {progress_data.get('status')}")
|
||||
print(f"Current Step: {progress_data.get('current_step')}")
|
||||
print(f"Overall Progress: {progress_data.get('overall_progress')}%")
|
||||
|
||||
# Check for Step 4 specifically
|
||||
step_results = progress_data.get('step_results', {})
|
||||
if 'step_04' in step_results:
|
||||
step4_result = step_results['step_04']
|
||||
print(f"\n📊 Step 4 Status: {step4_result.get('status')}")
|
||||
print(f"Step 4 Quality: {step4_result.get('quality_score')}")
|
||||
if step4_result.get('status') == 'error':
|
||||
print(f"Step 4 Error: {step4_result.get('error_message')}")
|
||||
else:
|
||||
print("⚠️ Step 4 results not yet available")
|
||||
else:
|
||||
print(f"❌ Progress endpoint failed: {progress_response.status}")
|
||||
else:
|
||||
print(f"❌ Calendar generation failed: {response.status}")
|
||||
error_text = await response.text()
|
||||
print(f"Error: {error_text}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error testing calendar generation: {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(test_calendar_generation())
|
||||
383
backend/test/test_calendar_generation_datasource_framework.py
Normal file
383
backend/test/test_calendar_generation_datasource_framework.py
Normal file
@@ -0,0 +1,383 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test Script for Calendar Generation Data Source Framework
|
||||
|
||||
Demonstrates the functionality of the scalable framework for evolving data sources
|
||||
in calendar generation without architectural changes.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# Add the backend directory to the Python path
|
||||
backend_dir = Path(__file__).parent
|
||||
sys.path.insert(0, str(backend_dir))
|
||||
|
||||
from services.calendar_generation_datasource_framework import (
|
||||
DataSourceRegistry,
|
||||
StrategyAwarePromptBuilder,
|
||||
QualityGateManager,
|
||||
DataSourceEvolutionManager,
|
||||
ContentStrategyDataSource,
|
||||
GapAnalysisDataSource,
|
||||
KeywordsDataSource,
|
||||
ContentPillarsDataSource,
|
||||
PerformanceDataSource,
|
||||
AIAnalysisDataSource
|
||||
)
|
||||
|
||||
|
||||
async def test_framework_initialization():
|
||||
"""Test framework initialization and component setup."""
|
||||
print("🧪 Testing Framework Initialization...")
|
||||
|
||||
try:
|
||||
# Initialize registry
|
||||
registry = DataSourceRegistry()
|
||||
print("✅ DataSourceRegistry initialized successfully")
|
||||
|
||||
# Initialize data sources
|
||||
content_strategy = ContentStrategyDataSource()
|
||||
gap_analysis = GapAnalysisDataSource()
|
||||
keywords = KeywordsDataSource()
|
||||
content_pillars = ContentPillarsDataSource()
|
||||
performance_data = PerformanceDataSource()
|
||||
ai_analysis = AIAnalysisDataSource()
|
||||
|
||||
print("✅ All data sources initialized successfully")
|
||||
|
||||
# Register data sources
|
||||
registry.register_source(content_strategy)
|
||||
registry.register_source(gap_analysis)
|
||||
registry.register_source(keywords)
|
||||
registry.register_source(content_pillars)
|
||||
registry.register_source(performance_data)
|
||||
registry.register_source(ai_analysis)
|
||||
|
||||
print("✅ All data sources registered successfully")
|
||||
|
||||
# Initialize framework components
|
||||
prompt_builder = StrategyAwarePromptBuilder(registry)
|
||||
quality_manager = QualityGateManager()
|
||||
evolution_manager = DataSourceEvolutionManager(registry)
|
||||
|
||||
print("✅ Framework components initialized successfully")
|
||||
|
||||
return registry, prompt_builder, quality_manager, evolution_manager
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Framework initialization failed: {e}")
|
||||
return None, None, None, None
|
||||
|
||||
|
||||
async def test_data_source_registry(registry):
|
||||
"""Test data source registry functionality."""
|
||||
print("\n🧪 Testing Data Source Registry...")
|
||||
|
||||
try:
|
||||
# Test registry status
|
||||
status = registry.get_registry_status()
|
||||
print(f"✅ Registry status: {status['total_sources']} sources, {status['active_sources']} active")
|
||||
|
||||
# Test source retrieval
|
||||
content_strategy = registry.get_source("content_strategy")
|
||||
if content_strategy:
|
||||
print(f"✅ Content strategy source retrieved: {content_strategy}")
|
||||
|
||||
# Test active sources
|
||||
active_sources = registry.get_active_sources()
|
||||
print(f"✅ Active sources: {len(active_sources)}")
|
||||
|
||||
# Test source types
|
||||
strategy_sources = registry.get_sources_by_type("strategy")
|
||||
print(f"✅ Strategy sources: {len(strategy_sources)}")
|
||||
|
||||
# Test priorities
|
||||
critical_sources = registry.get_sources_by_priority(1)
|
||||
print(f"✅ Critical priority sources: {len(critical_sources)}")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Registry test failed: {e}")
|
||||
return False
|
||||
|
||||
|
||||
async def test_data_source_validation(registry):
|
||||
"""Test data source validation functionality."""
|
||||
print("\n🧪 Testing Data Source Validation...")
|
||||
|
||||
try:
|
||||
# Validate all sources
|
||||
validation_results = await registry.validate_all_sources()
|
||||
print(f"✅ Validation completed for {len(validation_results)} sources")
|
||||
|
||||
# Check validation results
|
||||
for source_id, result in validation_results.items():
|
||||
if hasattr(result, 'quality_score'):
|
||||
print(f" - {source_id}: {result.quality_score:.2f} quality score")
|
||||
else:
|
||||
print(f" - {source_id}: {result.get('quality_score', 0):.2f} quality score")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Validation test failed: {e}")
|
||||
return False
|
||||
|
||||
|
||||
async def test_prompt_builder(prompt_builder):
|
||||
"""Test strategy-aware prompt builder functionality."""
|
||||
print("\n🧪 Testing Strategy-Aware Prompt Builder...")
|
||||
|
||||
try:
|
||||
# Test available steps
|
||||
available_steps = prompt_builder.get_available_steps()
|
||||
print(f"✅ Available steps: {len(available_steps)}")
|
||||
|
||||
# Test step dependencies
|
||||
step_1_deps = prompt_builder.get_step_dependencies("step_1_content_strategy_analysis")
|
||||
print(f"✅ Step 1 dependencies: {step_1_deps}")
|
||||
|
||||
# Test step requirements validation
|
||||
step_validation = prompt_builder.validate_step_requirements("step_1_content_strategy_analysis")
|
||||
print(f"✅ Step 1 validation: {step_validation['is_ready']}")
|
||||
|
||||
# Test prompt building (simplified)
|
||||
try:
|
||||
prompt = await prompt_builder.build_prompt("step_1_content_strategy_analysis", 1, 1)
|
||||
print(f"✅ Prompt built successfully (length: {len(prompt)} characters)")
|
||||
except Exception as e:
|
||||
print(f"⚠️ Prompt building failed (expected for test): {e}")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Prompt builder test failed: {e}")
|
||||
return False
|
||||
|
||||
|
||||
async def test_quality_gates(quality_manager):
|
||||
"""Test quality gate functionality."""
|
||||
print("\n🧪 Testing Quality Gates...")
|
||||
|
||||
try:
|
||||
# Test quality gate info
|
||||
gate_info = quality_manager.get_gate_info()
|
||||
print(f"✅ Quality gates: {len(gate_info)} gates available")
|
||||
|
||||
# Test specific gate validation
|
||||
sample_calendar_data = {
|
||||
"content_items": [
|
||||
{"title": "Sample Content 1", "type": "blog", "theme": "technology"},
|
||||
{"title": "Sample Content 2", "type": "video", "theme": "marketing"}
|
||||
]
|
||||
}
|
||||
|
||||
# Test all gates validation
|
||||
validation_results = await quality_manager.validate_all_gates(sample_calendar_data, "test_step")
|
||||
print(f"✅ All gates validation: {len(validation_results)} gates validated")
|
||||
|
||||
# Test specific gate validation
|
||||
content_uniqueness_result = await quality_manager.validate_specific_gate("content_uniqueness", sample_calendar_data, "test_step")
|
||||
print(f"✅ Content uniqueness validation: {content_uniqueness_result['passed']}")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Quality gates test failed: {e}")
|
||||
return False
|
||||
|
||||
|
||||
async def test_evolution_manager(evolution_manager):
|
||||
"""Test evolution manager functionality."""
|
||||
print("\n🧪 Testing Evolution Manager...")
|
||||
|
||||
try:
|
||||
# Test evolution status
|
||||
status = evolution_manager.get_evolution_status()
|
||||
print(f"✅ Evolution status for {len(status)} sources")
|
||||
|
||||
# Test evolution summary
|
||||
summary = evolution_manager.get_evolution_summary()
|
||||
print(f"✅ Evolution summary: {summary['sources_needing_evolution']} need evolution")
|
||||
|
||||
# Test evolution plan
|
||||
plan = evolution_manager.get_evolution_plan("content_strategy")
|
||||
print(f"✅ Content strategy evolution plan: {plan['is_ready_for_evolution']}")
|
||||
|
||||
# Test evolution (simplified)
|
||||
try:
|
||||
success = await evolution_manager.evolve_data_source("content_strategy", "2.5.0")
|
||||
print(f"✅ Evolution test: {'Success' if success else 'Failed'}")
|
||||
except Exception as e:
|
||||
print(f"⚠️ Evolution test failed (expected for test): {e}")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Evolution manager test failed: {e}")
|
||||
return False
|
||||
|
||||
|
||||
async def test_framework_integration(registry, prompt_builder, quality_manager, evolution_manager):
|
||||
"""Test framework integration and end-to-end functionality."""
|
||||
print("\n🧪 Testing Framework Integration...")
|
||||
|
||||
try:
|
||||
# Test comprehensive workflow
|
||||
print("📊 Testing comprehensive workflow...")
|
||||
|
||||
# 1. Get data from sources
|
||||
print(" 1. Retrieving data from sources...")
|
||||
for source_id in ["content_strategy", "gap_analysis", "keywords"]:
|
||||
try:
|
||||
data = await registry.get_data_with_dependencies(source_id, 1, 1)
|
||||
print(f" ✅ {source_id}: Data retrieved")
|
||||
except Exception as e:
|
||||
print(f" ⚠️ {source_id}: Data retrieval failed (expected)")
|
||||
|
||||
# 2. Build enhanced prompts
|
||||
print(" 2. Building enhanced prompts...")
|
||||
for step in ["step_1_content_strategy_analysis", "step_2_gap_analysis"]:
|
||||
try:
|
||||
base_prompt = await prompt_builder.build_prompt(step, 1, 1)
|
||||
print(f" ✅ {step}: Prompt built")
|
||||
except Exception as e:
|
||||
print(f" ⚠️ {step}: Prompt building failed (expected)")
|
||||
|
||||
# 3. Check evolution readiness
|
||||
print(" 3. Checking evolution readiness...")
|
||||
for source_id in ["content_strategy", "gap_analysis", "keywords"]:
|
||||
plan = evolution_manager.get_evolution_plan(source_id)
|
||||
print(f" ✅ {source_id}: Ready for evolution: {plan['is_ready_for_evolution']}")
|
||||
|
||||
print("✅ Framework integration test completed")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Framework integration test failed: {e}")
|
||||
return False
|
||||
|
||||
|
||||
async def test_scalability_features(registry, evolution_manager):
|
||||
"""Test scalability features of the framework."""
|
||||
print("\n🧪 Testing Scalability Features...")
|
||||
|
||||
try:
|
||||
# Test adding custom data source
|
||||
print("📈 Testing custom data source addition...")
|
||||
|
||||
# Create a custom data source (simplified)
|
||||
from services.calendar_generation_datasource_framework.interfaces import DataSourceInterface, DataSourceType, DataSourcePriority
|
||||
|
||||
class CustomDataSource(DataSourceInterface):
|
||||
def __init__(self):
|
||||
super().__init__("custom_source", DataSourceType.CUSTOM, DataSourcePriority.LOW)
|
||||
|
||||
async def get_data(self, user_id: int, strategy_id: int):
|
||||
return {"custom_data": "test"}
|
||||
|
||||
async def validate_data(self, data):
|
||||
return {"is_valid": True, "quality_score": 0.8}
|
||||
|
||||
async def enhance_data(self, data):
|
||||
return {**data, "enhanced": True}
|
||||
|
||||
# Register custom source
|
||||
custom_source = CustomDataSource()
|
||||
registry.register_source(custom_source)
|
||||
print("✅ Custom data source registered successfully")
|
||||
|
||||
# Test evolution config addition
|
||||
custom_config = {
|
||||
"current_version": "1.0.0",
|
||||
"target_version": "1.5.0",
|
||||
"enhancement_plan": ["Custom enhancement"],
|
||||
"implementation_steps": ["Implement custom enhancement"],
|
||||
"priority": "low",
|
||||
"estimated_effort": "low"
|
||||
}
|
||||
|
||||
evolution_manager.add_evolution_config("custom_source", custom_config)
|
||||
print("✅ Custom evolution config added successfully")
|
||||
|
||||
# Test framework status with new source
|
||||
status = registry.get_registry_status()
|
||||
print(f"✅ Framework now has {status['total_sources']} sources")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Scalability test failed: {e}")
|
||||
return False
|
||||
|
||||
|
||||
async def main():
|
||||
"""Run all framework tests."""
|
||||
print("🚀 Starting Calendar Generation Data Source Framework Tests...")
|
||||
print("=" * 80)
|
||||
|
||||
# Initialize framework
|
||||
registry, prompt_builder, quality_manager, evolution_manager = await test_framework_initialization()
|
||||
|
||||
if not all([registry, prompt_builder, quality_manager, evolution_manager]):
|
||||
print("❌ Framework initialization failed. Exiting.")
|
||||
return False
|
||||
|
||||
# Run individual component tests
|
||||
tests = [
|
||||
("Data Source Registry", test_data_source_registry, registry),
|
||||
("Data Source Validation", test_data_source_validation, registry),
|
||||
("Prompt Builder", test_prompt_builder, prompt_builder),
|
||||
("Quality Gates", test_quality_gates, quality_manager),
|
||||
("Evolution Manager", test_evolution_manager, evolution_manager),
|
||||
("Framework Integration", test_framework_integration, registry, prompt_builder, quality_manager, evolution_manager),
|
||||
("Scalability Features", test_scalability_features, registry, evolution_manager)
|
||||
]
|
||||
|
||||
results = []
|
||||
for test_name, test_func, *args in tests:
|
||||
try:
|
||||
result = await test_func(*args)
|
||||
results.append((test_name, result))
|
||||
except Exception as e:
|
||||
print(f"❌ {test_name} test failed with exception: {e}")
|
||||
results.append((test_name, False))
|
||||
|
||||
# Print test summary
|
||||
print("\n" + "=" * 80)
|
||||
print("📋 Test Results Summary:")
|
||||
|
||||
passed = 0
|
||||
total = len(results)
|
||||
|
||||
for test_name, result in results:
|
||||
status = "✅ PASSED" if result else "❌ FAILED"
|
||||
print(f" {status} - {test_name}")
|
||||
if result:
|
||||
passed += 1
|
||||
|
||||
print(f"\n🎯 Overall Results: {passed}/{total} tests passed")
|
||||
|
||||
if passed == total:
|
||||
print("🎉 All tests passed! Framework is working correctly.")
|
||||
print("\n✅ Framework Features Verified:")
|
||||
print(" - Scalable data source management")
|
||||
print(" - Strategy-aware prompt building")
|
||||
print(" - Quality gate integration")
|
||||
print(" - Evolution management")
|
||||
print(" - Framework integration")
|
||||
print(" - Scalability and extensibility")
|
||||
return True
|
||||
else:
|
||||
print("⚠️ Some tests failed. Please check the implementation.")
|
||||
return False
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Run the tests
|
||||
success = asyncio.run(main())
|
||||
sys.exit(0 if success else 1)
|
||||
228
backend/test/test_enhanced_prompt_generation.py
Normal file
228
backend/test/test_enhanced_prompt_generation.py
Normal file
@@ -0,0 +1,228 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test Script for Enhanced LinkedIn Prompt Generation
|
||||
|
||||
This script demonstrates how the enhanced LinkedIn prompt generator analyzes
|
||||
generated content and creates context-aware image prompts.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# Add the backend directory to the Python path
|
||||
backend_path = Path(__file__).parent
|
||||
sys.path.insert(0, str(backend_path))
|
||||
|
||||
from loguru import logger
|
||||
|
||||
# Configure logging
|
||||
logger.remove()
|
||||
logger.add(sys.stdout, colorize=True, format="<level>{level}</level>| {message}")
|
||||
|
||||
|
||||
async def test_enhanced_prompt_generation():
|
||||
"""Test the enhanced LinkedIn prompt generation with content analysis."""
|
||||
|
||||
logger.info("🧪 Testing Enhanced LinkedIn Prompt Generation")
|
||||
logger.info("=" * 70)
|
||||
|
||||
try:
|
||||
# Import the enhanced prompt generator
|
||||
from services.linkedin.image_prompts import LinkedInPromptGenerator
|
||||
|
||||
# Initialize the service
|
||||
prompt_generator = LinkedInPromptGenerator()
|
||||
logger.success("✅ LinkedIn Prompt Generator initialized successfully")
|
||||
|
||||
# Test cases with different types of LinkedIn content
|
||||
test_cases = [
|
||||
{
|
||||
'name': 'AI Marketing Post',
|
||||
'content': {
|
||||
'topic': 'AI in Marketing',
|
||||
'industry': 'Technology',
|
||||
'content_type': 'post',
|
||||
'content': """🚀 Exciting news! Artificial Intelligence is revolutionizing how we approach marketing strategies.
|
||||
|
||||
Here are 3 game-changing ways AI is transforming the industry:
|
||||
|
||||
1️⃣ **Predictive Analytics**: AI algorithms can now predict customer behavior with 95% accuracy, allowing marketers to create hyper-personalized campaigns.
|
||||
|
||||
2️⃣ **Content Optimization**: Machine learning models analyze engagement patterns to optimize content timing, format, and messaging for maximum impact.
|
||||
|
||||
3️⃣ **Automated Personalization**: AI-powered tools automatically adjust marketing messages based on individual user preferences and behavior.
|
||||
|
||||
The future of marketing is here, and it's powered by AI! 🎯
|
||||
|
||||
What's your experience with AI in marketing? Share your thoughts below! 👇
|
||||
|
||||
#AIMarketing #DigitalTransformation #MarketingInnovation #TechTrends #FutureOfMarketing"""
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'Leadership Article',
|
||||
'content': {
|
||||
'topic': 'Building High-Performance Teams',
|
||||
'industry': 'Business',
|
||||
'content_type': 'article',
|
||||
'content': """Building High-Performance Teams: A Comprehensive Guide
|
||||
|
||||
In today's competitive business landscape, the ability to build and lead high-performance teams is not just a skill—it's a strategic imperative. After 15 years of leading teams across various industries, I've identified the key principles that consistently drive exceptional results.
|
||||
|
||||
**The Foundation: Clear Vision and Purpose**
|
||||
Every high-performance team starts with a crystal-clear understanding of their mission. Team members need to know not just what they're doing, but why it matters. This creates intrinsic motivation that external rewards simply cannot match.
|
||||
|
||||
**Communication: The Lifeblood of Success**
|
||||
Effective communication in high-performance teams goes beyond regular meetings. It involves creating an environment where feedback flows freely, ideas are shared without fear, and every voice is heard and valued.
|
||||
|
||||
**Trust and Psychological Safety**
|
||||
High-performance teams operate in environments where team members feel safe to take risks, make mistakes, and learn from failures. This psychological safety is the bedrock of innovation and continuous improvement.
|
||||
|
||||
**Continuous Learning and Adaptation**
|
||||
The best teams never rest on their laurels. They continuously seek new knowledge, adapt to changing circumstances, and evolve their approaches based on results and feedback.
|
||||
|
||||
**Results and Accountability**
|
||||
While process matters, high-performance teams are ultimately measured by their results. Clear metrics, regular check-ins, and a culture of accountability ensure that the team stays focused on delivering value.
|
||||
|
||||
Building high-performance teams is both an art and a science. It requires patience, persistence, and a genuine commitment to developing people. The investment pays dividends not just in results, but in the satisfaction of seeing individuals grow and teams achieve what once seemed impossible.
|
||||
|
||||
What strategies have you found most effective in building high-performance teams? Share your insights in the comments below."""
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'Data Analytics Carousel',
|
||||
'content': {
|
||||
'topic': 'Data-Driven Decision Making',
|
||||
'industry': 'Finance',
|
||||
'content_type': 'carousel',
|
||||
'content': """📊 Data-Driven Decision Making: Your Competitive Advantage
|
||||
|
||||
Slide 1: The Power of Data
|
||||
• 73% of companies using data-driven decision making report improved performance
|
||||
• Data-driven organizations are 23x more likely to acquire customers
|
||||
• 58% of executives say data analytics has improved their decision-making process
|
||||
|
||||
Slide 2: Key Metrics to Track
|
||||
• Customer Acquisition Cost (CAC)
|
||||
• Customer Lifetime Value (CLV)
|
||||
• Conversion Rates
|
||||
• Churn Rate
|
||||
• Revenue Growth
|
||||
|
||||
Slide 3: Implementation Steps
|
||||
1. Define clear objectives
|
||||
2. Identify relevant data sources
|
||||
3. Establish data quality standards
|
||||
4. Build analytical capabilities
|
||||
5. Create feedback loops
|
||||
|
||||
Slide 4: Common Pitfalls
|
||||
• Analysis paralysis
|
||||
• Ignoring qualitative insights
|
||||
• Not validating assumptions
|
||||
• Over-relying on historical data
|
||||
• Poor data visualization
|
||||
|
||||
Slide 5: Success Stories
|
||||
• Netflix: 75% of viewing decisions influenced by data
|
||||
• Amazon: Dynamic pricing increases revenue by 25%
|
||||
• Spotify: Personalized recommendations drive 40% of listening time
|
||||
|
||||
Slide 6: Getting Started
|
||||
• Start small with key metrics
|
||||
• Invest in data literacy training
|
||||
• Use visualization tools
|
||||
• Establish regular review cycles
|
||||
• Celebrate data-driven wins
|
||||
|
||||
Ready to transform your decision-making process? Let's discuss your data strategy! 💬
|
||||
|
||||
#DataDriven #Analytics #BusinessIntelligence #DecisionMaking #Finance #Strategy"""
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
# Test each case
|
||||
for i, test_case in enumerate(test_cases, 1):
|
||||
logger.info(f"\n📝 Test Case {i}: {test_case['name']}")
|
||||
logger.info("-" * 50)
|
||||
|
||||
# Generate prompts using the enhanced generator
|
||||
prompts = await prompt_generator.generate_three_prompts(
|
||||
test_case['content'],
|
||||
aspect_ratio="1:1"
|
||||
)
|
||||
|
||||
if prompts and len(prompts) >= 3:
|
||||
logger.success(f"✅ Generated {len(prompts)} context-aware prompts")
|
||||
|
||||
# Display each prompt
|
||||
for j, prompt in enumerate(prompts, 1):
|
||||
logger.info(f"\n🎨 Prompt {j}: {prompt['style']}")
|
||||
logger.info(f" Description: {prompt['description']}")
|
||||
logger.info(f" Content Context: {prompt.get('content_context', 'N/A')}")
|
||||
|
||||
# Show a preview of the prompt
|
||||
prompt_text = prompt['prompt']
|
||||
if len(prompt_text) > 200:
|
||||
prompt_text = prompt_text[:200] + "..."
|
||||
logger.info(f" Prompt Preview: {prompt_text}")
|
||||
|
||||
# Validate prompt quality
|
||||
quality_result = await prompt_generator.validate_prompt_quality(prompt)
|
||||
if quality_result.get('valid'):
|
||||
logger.success(f" ✅ Quality Score: {quality_result['overall_score']}/100")
|
||||
else:
|
||||
logger.warning(f" ⚠️ Quality Score: {quality_result.get('overall_score', 'N/A')}/100")
|
||||
else:
|
||||
logger.error(f"❌ Failed to generate prompts for {test_case['name']}")
|
||||
|
||||
# Test content analysis functionality directly
|
||||
logger.info(f"\n🔍 Testing Content Analysis Functionality")
|
||||
logger.info("-" * 50)
|
||||
|
||||
test_content = test_cases[0]['content']['content']
|
||||
content_analysis = prompt_generator._analyze_content_for_image_context(
|
||||
test_content,
|
||||
test_cases[0]['content']['content_type']
|
||||
)
|
||||
|
||||
logger.info("Content Analysis Results:")
|
||||
for key, value in content_analysis.items():
|
||||
logger.info(f" {key}: {value}")
|
||||
|
||||
logger.info("=" * 70)
|
||||
logger.success("🎉 Enhanced LinkedIn Prompt Generation Test Completed Successfully!")
|
||||
|
||||
return True
|
||||
|
||||
except ImportError as e:
|
||||
logger.error(f"❌ Import Error: {e}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Test Failed: {e}")
|
||||
import traceback
|
||||
logger.error(f"Traceback: {traceback.format_exc()}")
|
||||
return False
|
||||
|
||||
|
||||
async def main():
|
||||
"""Main test function."""
|
||||
logger.info("🚀 Starting Enhanced LinkedIn Prompt Generation Tests")
|
||||
|
||||
success = await test_enhanced_prompt_generation()
|
||||
|
||||
if success:
|
||||
logger.success("✅ All tests passed! The enhanced prompt generation is working correctly.")
|
||||
sys.exit(0)
|
||||
else:
|
||||
logger.error("❌ Some tests failed. Please check the errors above.")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Run the async test
|
||||
asyncio.run(main())
|
||||
201
backend/test/test_enhanced_strategy_processing.py
Normal file
201
backend/test/test_enhanced_strategy_processing.py
Normal file
@@ -0,0 +1,201 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test script for Enhanced Strategy Data Processing
|
||||
Verifies that the enhanced strategy data processing is working correctly.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# Add the backend directory to the Python path
|
||||
backend_dir = Path(__file__).parent
|
||||
sys.path.insert(0, str(backend_dir))
|
||||
|
||||
from services.content_planning_db import ContentPlanningDBService
|
||||
|
||||
async def test_enhanced_strategy_processing():
|
||||
"""Test the enhanced strategy data processing functionality."""
|
||||
print("🧪 Testing Enhanced Strategy Data Processing...")
|
||||
|
||||
try:
|
||||
# Initialize the database service
|
||||
db_service = ContentPlanningDBService()
|
||||
|
||||
# Test with a sample strategy ID
|
||||
strategy_id = 1 # You can change this to test with different strategies
|
||||
|
||||
print(f"📊 Testing strategy data retrieval for strategy ID: {strategy_id}")
|
||||
|
||||
# Test the enhanced strategy data retrieval
|
||||
strategy_data = await db_service.get_strategy_data(strategy_id)
|
||||
|
||||
if strategy_data:
|
||||
print("✅ Strategy data retrieved successfully!")
|
||||
print(f"📈 Strategy data contains {len(strategy_data)} fields")
|
||||
|
||||
# Check for enhanced fields
|
||||
enhanced_fields = [
|
||||
"strategy_analysis",
|
||||
"quality_indicators",
|
||||
"data_completeness",
|
||||
"strategic_alignment",
|
||||
"quality_gate_data",
|
||||
"prompt_chain_data"
|
||||
]
|
||||
|
||||
print("\n🔍 Checking for enhanced strategy fields:")
|
||||
for field in enhanced_fields:
|
||||
if field in strategy_data:
|
||||
print(f" ✅ {field}: Present")
|
||||
if isinstance(strategy_data[field], dict):
|
||||
print(f" Contains {len(strategy_data[field])} sub-fields")
|
||||
else:
|
||||
print(f" ❌ {field}: Missing")
|
||||
|
||||
# Check strategy analysis
|
||||
if "strategy_analysis" in strategy_data:
|
||||
analysis = strategy_data["strategy_analysis"]
|
||||
print(f"\n📊 Strategy Analysis:")
|
||||
print(f" - Completion Percentage: {analysis.get('completion_percentage', 0)}%")
|
||||
print(f" - Filled Fields: {analysis.get('filled_fields', 0)}/{analysis.get('total_fields', 30)}")
|
||||
print(f" - Data Quality Score: {analysis.get('data_quality_score', 0)}%")
|
||||
print(f" - Strategy Coherence: {analysis.get('strategy_coherence', {}).get('overall_coherence', 0)}%")
|
||||
|
||||
# Check quality indicators
|
||||
if "quality_indicators" in strategy_data:
|
||||
quality = strategy_data["quality_indicators"]
|
||||
print(f"\n🎯 Quality Indicators:")
|
||||
print(f" - Data Completeness: {quality.get('data_completeness', 0)}%")
|
||||
print(f" - Strategic Alignment: {quality.get('strategic_alignment', 0)}%")
|
||||
print(f" - Market Relevance: {quality.get('market_relevance', 0)}%")
|
||||
print(f" - Audience Alignment: {quality.get('audience_alignment', 0)}%")
|
||||
print(f" - Content Strategy Coherence: {quality.get('content_strategy_coherence', 0)}%")
|
||||
print(f" - Overall Quality Score: {quality.get('overall_quality_score', 0)}%")
|
||||
|
||||
# Check quality gate data
|
||||
if "quality_gate_data" in strategy_data:
|
||||
quality_gates = strategy_data["quality_gate_data"]
|
||||
print(f"\n🚪 Quality Gate Data:")
|
||||
for gate_name, gate_data in quality_gates.items():
|
||||
if isinstance(gate_data, dict):
|
||||
print(f" - {gate_name}: {len(gate_data)} fields")
|
||||
else:
|
||||
print(f" - {gate_name}: {type(gate_data).__name__}")
|
||||
|
||||
# Check prompt chain data
|
||||
if "prompt_chain_data" in strategy_data:
|
||||
prompt_chain = strategy_data["prompt_chain_data"]
|
||||
print(f"\n🔗 Prompt Chain Data:")
|
||||
for step_name, step_data in prompt_chain.items():
|
||||
if isinstance(step_data, dict):
|
||||
print(f" - {step_name}: {len(step_data)} sub-sections")
|
||||
else:
|
||||
print(f" - {step_name}: {type(step_data).__name__}")
|
||||
|
||||
print(f"\n✅ Enhanced Strategy Data Processing Test PASSED!")
|
||||
return True
|
||||
|
||||
else:
|
||||
print("❌ No strategy data retrieved")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error during enhanced strategy data processing test: {str(e)}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
async def test_comprehensive_user_data():
|
||||
"""Test the comprehensive user data retrieval with enhanced strategy data."""
|
||||
print("\n🧪 Testing Comprehensive User Data with Enhanced Strategy...")
|
||||
|
||||
try:
|
||||
# Initialize the database service
|
||||
db_service = ContentPlanningDBService()
|
||||
|
||||
# Test with a sample user ID and strategy ID
|
||||
user_id = 1
|
||||
strategy_id = 1
|
||||
|
||||
print(f"📊 Testing comprehensive user data for user {user_id} with strategy {strategy_id}")
|
||||
|
||||
# Test the comprehensive user data retrieval
|
||||
user_data = await calendar_service._get_comprehensive_user_data(user_id, strategy_id)
|
||||
|
||||
if user_data:
|
||||
print("✅ Comprehensive user data retrieved successfully!")
|
||||
print(f"📈 User data contains {len(user_data)} fields")
|
||||
|
||||
# Check for enhanced strategy fields in user data
|
||||
enhanced_fields = [
|
||||
"strategy_analysis",
|
||||
"quality_indicators",
|
||||
"data_completeness",
|
||||
"strategic_alignment",
|
||||
"quality_gate_data",
|
||||
"prompt_chain_data"
|
||||
]
|
||||
|
||||
print("\n🔍 Checking for enhanced strategy fields in user data:")
|
||||
for field in enhanced_fields:
|
||||
if field in user_data:
|
||||
print(f" ✅ {field}: Present")
|
||||
if isinstance(user_data[field], dict):
|
||||
print(f" Contains {len(user_data[field])} sub-fields")
|
||||
else:
|
||||
print(f" ❌ {field}: Missing")
|
||||
|
||||
# Check strategy data quality
|
||||
if "strategy_data" in user_data:
|
||||
strategy_data = user_data["strategy_data"]
|
||||
print(f"\n📊 Strategy Data Quality:")
|
||||
print(f" - Strategy ID: {strategy_data.get('strategy_id', 'N/A')}")
|
||||
print(f" - Strategy Name: {strategy_data.get('strategy_name', 'N/A')}")
|
||||
print(f" - Industry: {strategy_data.get('industry', 'N/A')}")
|
||||
print(f" - Content Pillars: {len(strategy_data.get('content_pillars', []))} pillars")
|
||||
print(f" - Target Audience: {len(strategy_data.get('target_audience', {}))} audience fields")
|
||||
|
||||
print(f"\n✅ Comprehensive User Data Test PASSED!")
|
||||
return True
|
||||
|
||||
else:
|
||||
print("❌ No comprehensive user data retrieved")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error during comprehensive user data test: {str(e)}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
async def main():
|
||||
"""Run all tests for enhanced strategy data processing."""
|
||||
print("🚀 Starting Enhanced Strategy Data Processing Tests...")
|
||||
print("=" * 60)
|
||||
|
||||
# Test 1: Enhanced Strategy Data Processing
|
||||
test1_passed = await test_enhanced_strategy_processing()
|
||||
|
||||
# Test 2: Comprehensive User Data
|
||||
test2_passed = await test_comprehensive_user_data()
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("📋 Test Results Summary:")
|
||||
print(f" ✅ Enhanced Strategy Data Processing: {'PASSED' if test1_passed else 'FAILED'}")
|
||||
print(f" ✅ Comprehensive User Data: {'PASSED' if test2_passed else 'FAILED'}")
|
||||
|
||||
if test1_passed and test2_passed:
|
||||
print("\n🎉 All Enhanced Strategy Data Processing Tests PASSED!")
|
||||
print("✅ The enhanced strategy data processing is working correctly.")
|
||||
print("✅ Ready for 12-step prompt chaining and quality gates integration.")
|
||||
return True
|
||||
else:
|
||||
print("\n❌ Some tests failed. Please check the implementation.")
|
||||
return False
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Run the tests
|
||||
success = asyncio.run(main())
|
||||
sys.exit(0 if success else 1)
|
||||
232
backend/test/test_facebook_writer.py
Normal file
232
backend/test/test_facebook_writer.py
Normal file
@@ -0,0 +1,232 @@
|
||||
"""Test script for Facebook Writer API endpoints."""
|
||||
|
||||
import requests
|
||||
import json
|
||||
from typing import Dict, Any
|
||||
|
||||
# Base URL for the API
|
||||
BASE_URL = "http://localhost:8000"
|
||||
|
||||
def test_health_check():
|
||||
"""Test the health check endpoint."""
|
||||
try:
|
||||
response = requests.get(f"{BASE_URL}/api/facebook-writer/health")
|
||||
print(f"Health Check: {response.status_code}")
|
||||
if response.status_code == 200:
|
||||
print(f"Response: {response.json()}")
|
||||
return response.status_code == 200
|
||||
except Exception as e:
|
||||
print(f"Health check failed: {e}")
|
||||
return False
|
||||
|
||||
def test_get_tools():
|
||||
"""Test getting available tools."""
|
||||
try:
|
||||
response = requests.get(f"{BASE_URL}/api/facebook-writer/tools")
|
||||
print(f"Get Tools: {response.status_code}")
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
print(f"Available tools: {data['total_count']}")
|
||||
for tool in data['tools'][:3]: # Show first 3 tools
|
||||
print(f" - {tool['name']}: {tool['description']}")
|
||||
return response.status_code == 200
|
||||
except Exception as e:
|
||||
print(f"Get tools failed: {e}")
|
||||
return False
|
||||
|
||||
def test_generate_post():
|
||||
"""Test Facebook post generation."""
|
||||
payload = {
|
||||
"business_type": "Fitness coach",
|
||||
"target_audience": "Fitness enthusiasts aged 25-35",
|
||||
"post_goal": "Increase engagement",
|
||||
"post_tone": "Inspirational",
|
||||
"include": "Success story, workout tips",
|
||||
"avoid": "Generic advice",
|
||||
"media_type": "Image",
|
||||
"advanced_options": {
|
||||
"use_hook": True,
|
||||
"use_story": True,
|
||||
"use_cta": True,
|
||||
"use_question": True,
|
||||
"use_emoji": True,
|
||||
"use_hashtags": True
|
||||
}
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(
|
||||
f"{BASE_URL}/api/facebook-writer/post/generate",
|
||||
json=payload,
|
||||
headers={"Content-Type": "application/json"}
|
||||
)
|
||||
print(f"Generate Post: {response.status_code}")
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
if data['success']:
|
||||
print(f"Post generated successfully!")
|
||||
print(f"Content preview: {data['content'][:100]}...")
|
||||
if data.get('analytics'):
|
||||
print(f"Expected reach: {data['analytics']['expected_reach']}")
|
||||
else:
|
||||
print(f"Generation failed: {data.get('error', 'Unknown error')}")
|
||||
else:
|
||||
print(f"Request failed: {response.text}")
|
||||
return response.status_code == 200
|
||||
except Exception as e:
|
||||
print(f"Generate post failed: {e}")
|
||||
return False
|
||||
|
||||
def test_generate_story():
|
||||
"""Test Facebook story generation."""
|
||||
payload = {
|
||||
"business_type": "Fashion brand",
|
||||
"target_audience": "Fashion enthusiasts aged 18-30",
|
||||
"story_type": "Product showcase",
|
||||
"story_tone": "Fun",
|
||||
"include": "Behind the scenes",
|
||||
"avoid": "Too much text",
|
||||
"visual_options": {
|
||||
"background_type": "Gradient",
|
||||
"text_overlay": True,
|
||||
"stickers": True,
|
||||
"interactive_elements": True
|
||||
}
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(
|
||||
f"{BASE_URL}/api/facebook-writer/story/generate",
|
||||
json=payload,
|
||||
headers={"Content-Type": "application/json"}
|
||||
)
|
||||
print(f"Generate Story: {response.status_code}")
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
if data['success']:
|
||||
print(f"Story generated successfully!")
|
||||
print(f"Content preview: {data['content'][:100]}...")
|
||||
if data.get('visual_suggestions'):
|
||||
print(f"Visual suggestions: {len(data['visual_suggestions'])} items")
|
||||
else:
|
||||
print(f"Generation failed: {data.get('error', 'Unknown error')}")
|
||||
return response.status_code == 200
|
||||
except Exception as e:
|
||||
print(f"Generate story failed: {e}")
|
||||
return False
|
||||
|
||||
def test_generate_ad_copy():
|
||||
"""Test Facebook ad copy generation."""
|
||||
payload = {
|
||||
"business_type": "E-commerce store",
|
||||
"product_service": "Wireless headphones",
|
||||
"ad_objective": "Conversions",
|
||||
"ad_format": "Single image",
|
||||
"target_audience": "Tech enthusiasts and music lovers",
|
||||
"targeting_options": {
|
||||
"age_group": "25-34",
|
||||
"interests": "Technology, Music, Audio equipment",
|
||||
"location": "United States"
|
||||
},
|
||||
"unique_selling_proposition": "Premium sound quality at affordable prices",
|
||||
"offer_details": "20% off for first-time buyers",
|
||||
"budget_range": "Medium"
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(
|
||||
f"{BASE_URL}/api/facebook-writer/ad-copy/generate",
|
||||
json=payload,
|
||||
headers={"Content-Type": "application/json"}
|
||||
)
|
||||
print(f"Generate Ad Copy: {response.status_code}")
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
if data['success']:
|
||||
print(f"Ad copy generated successfully!")
|
||||
if data.get('primary_ad_copy'):
|
||||
print(f"Headline: {data['primary_ad_copy'].get('headline', 'N/A')}")
|
||||
if data.get('performance_predictions'):
|
||||
print(f"Estimated reach: {data['performance_predictions']['estimated_reach']}")
|
||||
else:
|
||||
print(f"Generation failed: {data.get('error', 'Unknown error')}")
|
||||
return response.status_code == 200
|
||||
except Exception as e:
|
||||
print(f"Generate ad copy failed: {e}")
|
||||
return False
|
||||
|
||||
def test_analyze_engagement():
|
||||
"""Test engagement analysis."""
|
||||
payload = {
|
||||
"content": "🚀 Ready to transform your fitness journey? Our new 30-day challenge is here! Join thousands who've already seen amazing results. What's your biggest fitness goal? 💪 #FitnessMotivation #Challenge #Transformation",
|
||||
"content_type": "Post",
|
||||
"analysis_type": "Performance prediction",
|
||||
"business_type": "Fitness coach",
|
||||
"target_audience": "Fitness enthusiasts"
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(
|
||||
f"{BASE_URL}/api/facebook-writer/engagement/analyze",
|
||||
json=payload,
|
||||
headers={"Content-Type": "application/json"}
|
||||
)
|
||||
print(f"Analyze Engagement: {response.status_code}")
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
if data['success']:
|
||||
print(f"Analysis completed successfully!")
|
||||
print(f"Content score: {data.get('content_score', 'N/A')}/100")
|
||||
if data.get('engagement_metrics'):
|
||||
print(f"Predicted engagement: {data['engagement_metrics']['predicted_engagement_rate']}")
|
||||
else:
|
||||
print(f"Analysis failed: {data.get('error', 'Unknown error')}")
|
||||
return response.status_code == 200
|
||||
except Exception as e:
|
||||
print(f"Analyze engagement failed: {e}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
"""Run all tests."""
|
||||
print("🧪 Testing Facebook Writer API Endpoints")
|
||||
print("=" * 50)
|
||||
|
||||
tests = [
|
||||
("Health Check", test_health_check),
|
||||
("Get Tools", test_get_tools),
|
||||
("Generate Post", test_generate_post),
|
||||
("Generate Story", test_generate_story),
|
||||
("Generate Ad Copy", test_generate_ad_copy),
|
||||
("Analyze Engagement", test_analyze_engagement)
|
||||
]
|
||||
|
||||
results = []
|
||||
for test_name, test_func in tests:
|
||||
print(f"\n🔍 Running {test_name}...")
|
||||
try:
|
||||
success = test_func()
|
||||
results.append((test_name, success))
|
||||
status = "✅ PASS" if success else "❌ FAIL"
|
||||
print(f"{status}")
|
||||
except Exception as e:
|
||||
print(f"❌ FAIL - {e}")
|
||||
results.append((test_name, False))
|
||||
|
||||
print(f"\n📊 Test Results Summary")
|
||||
print("=" * 50)
|
||||
passed = sum(1 for _, success in results if success)
|
||||
total = len(results)
|
||||
|
||||
for test_name, success in results:
|
||||
status = "✅ PASS" if success else "❌ FAIL"
|
||||
print(f"{status} {test_name}")
|
||||
|
||||
print(f"\nOverall: {passed}/{total} tests passed ({passed/total*100:.1f}%)")
|
||||
|
||||
if passed == total:
|
||||
print("🎉 All tests passed! Facebook Writer API is ready to use.")
|
||||
else:
|
||||
print("⚠️ Some tests failed. Check the server logs for details.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
140
backend/test/test_full_flow.py
Normal file
140
backend/test/test_full_flow.py
Normal file
@@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test the full 12-step calendar generation process to verify Step 5 fix.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import time
|
||||
from loguru import logger
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Add the backend directory to the path
|
||||
backend_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
if backend_dir not in sys.path:
|
||||
sys.path.insert(0, backend_dir)
|
||||
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.orchestrator import PromptChainOrchestrator
|
||||
|
||||
async def test_full_12_step_process():
|
||||
"""Test the complete 12-step process to verify Step 5 fix."""
|
||||
try:
|
||||
logger.info("🧪 Testing full 12-step calendar generation process")
|
||||
|
||||
# Create orchestrator
|
||||
logger.info("✅ Creating orchestrator...")
|
||||
orchestrator = PromptChainOrchestrator()
|
||||
|
||||
# Test parameters
|
||||
user_id = 1
|
||||
strategy_id = 1
|
||||
calendar_type = "monthly"
|
||||
industry = "technology"
|
||||
business_size = "sme"
|
||||
|
||||
logger.info(f"🎯 Starting calendar generation for user {user_id}, strategy {strategy_id}")
|
||||
logger.info(f"📋 Parameters: {calendar_type}, {industry}, {business_size}")
|
||||
|
||||
# Start the full process
|
||||
start_time = time.time()
|
||||
|
||||
# Generate calendar using the orchestrator's main method
|
||||
logger.info("🚀 Executing full 12-step process...")
|
||||
final_calendar = await orchestrator.generate_calendar(
|
||||
user_id=user_id,
|
||||
strategy_id=strategy_id,
|
||||
calendar_type=calendar_type,
|
||||
industry=industry,
|
||||
business_size=business_size
|
||||
)
|
||||
|
||||
# Extract context from the result for analysis
|
||||
context = {
|
||||
"step_results": final_calendar.get("step_results", {}),
|
||||
"quality_scores": final_calendar.get("quality_scores", {})
|
||||
}
|
||||
|
||||
execution_time = time.time() - start_time
|
||||
|
||||
logger.info(f"✅ Full 12-step process completed in {execution_time:.2f} seconds")
|
||||
|
||||
# Analyze results
|
||||
step_results = context.get("step_results", {})
|
||||
quality_scores = context.get("quality_scores", {})
|
||||
|
||||
logger.info("📊 Step Results Analysis:")
|
||||
logger.info(f" Total steps executed: {len(step_results)}")
|
||||
|
||||
# Check each step
|
||||
for step_key in sorted(step_results.keys()):
|
||||
step_result = step_results[step_key]
|
||||
status = step_result.get("status", "unknown")
|
||||
quality_score = step_result.get("quality_score", 0.0)
|
||||
validation_passed = step_result.get("validation_passed", False)
|
||||
|
||||
logger.info(f" {step_key}: status={status}, quality={quality_score:.2f}, validation_passed={validation_passed}")
|
||||
|
||||
if status == "failed" or status == "error":
|
||||
logger.error(f" ❌ {step_key} failed with status: {status}")
|
||||
error_message = step_result.get("error_message", "No error message")
|
||||
logger.error(f" Error: {error_message}")
|
||||
|
||||
# Check Step 5 specifically
|
||||
step_05_result = step_results.get("step_05", {})
|
||||
if step_05_result:
|
||||
step_05_status = step_05_result.get("status", "unknown")
|
||||
step_05_quality = step_05_result.get("quality_score", 0.0)
|
||||
step_05_validation = step_05_result.get("validation_passed", False)
|
||||
|
||||
logger.info(f"🎯 Step 5 Analysis:")
|
||||
logger.info(f" Status: {step_05_status}")
|
||||
logger.info(f" Quality Score: {step_05_quality:.2f}")
|
||||
logger.info(f" Validation Passed: {step_05_validation}")
|
||||
|
||||
if step_05_status == "completed" and step_05_validation:
|
||||
logger.info("✅ Step 5 FIX VERIFIED - Working correctly in full process!")
|
||||
else:
|
||||
logger.error("❌ Step 5 still has issues in full process")
|
||||
else:
|
||||
logger.error("❌ Step 5 result not found in step_results")
|
||||
|
||||
# Overall quality
|
||||
overall_quality = sum(quality_scores.values()) / len(quality_scores) if quality_scores else 0.0
|
||||
logger.info(f"📊 Overall Quality Score: {overall_quality:.2f}")
|
||||
|
||||
# Success criteria
|
||||
completed_steps = sum(1 for result in step_results.values() if result.get("status") == "completed")
|
||||
total_steps = len(step_results)
|
||||
|
||||
logger.info(f"📊 Process Summary:")
|
||||
logger.info(f" Completed Steps: {completed_steps}/{total_steps}")
|
||||
logger.info(f" Success Rate: {(completed_steps/total_steps)*100:.1f}%")
|
||||
logger.info(f" Overall Quality: {overall_quality:.2f}")
|
||||
|
||||
if completed_steps == total_steps and overall_quality > 0.8:
|
||||
logger.info("🎉 SUCCESS: Full 12-step process completed successfully!")
|
||||
return True
|
||||
else:
|
||||
logger.error("❌ FAILURE: Full 12-step process had issues")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Error in full 12-step process test: {str(e)}")
|
||||
import traceback
|
||||
logger.error(f"📋 Traceback: {traceback.format_exc()}")
|
||||
return False
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Configure logging
|
||||
logger.remove()
|
||||
logger.add(sys.stderr, level="INFO", format="<green>{time:HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>")
|
||||
|
||||
# Run the test
|
||||
success = asyncio.run(test_full_12_step_process())
|
||||
|
||||
if success:
|
||||
print("\n🎉 Test completed successfully!")
|
||||
sys.exit(0)
|
||||
else:
|
||||
print("\n❌ Test failed!")
|
||||
sys.exit(1)
|
||||
62
backend/test/test_grounding_flow.py
Normal file
62
backend/test/test_grounding_flow.py
Normal file
@@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test script to debug the grounding data flow
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Add the backend directory to the path
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
from services.linkedin_service import LinkedInService
|
||||
from models.linkedin_models import LinkedInPostRequest, GroundingLevel
|
||||
|
||||
async def test_grounding_flow():
|
||||
"""Test the grounding data flow"""
|
||||
try:
|
||||
print("🔍 Testing grounding data flow...")
|
||||
|
||||
# Initialize the service
|
||||
service = LinkedInService()
|
||||
print("✅ LinkedInService initialized")
|
||||
|
||||
# Create a test request
|
||||
request = LinkedInPostRequest(
|
||||
topic="AI in healthcare transformation",
|
||||
industry="Healthcare",
|
||||
grounding_level=GroundingLevel.ENHANCED,
|
||||
include_citations=True,
|
||||
research_enabled=True,
|
||||
search_engine="google",
|
||||
max_length=2000
|
||||
)
|
||||
print("✅ Test request created")
|
||||
|
||||
# Generate post
|
||||
print("🚀 Generating LinkedIn post...")
|
||||
response = await service.generate_linkedin_post(request)
|
||||
|
||||
if response.success:
|
||||
print("✅ Post generated successfully!")
|
||||
print(f"📊 Research sources count: {len(response.research_sources) if response.research_sources else 0}")
|
||||
print(f"📝 Citations count: {len(response.data.citations) if response.data.citations else 0}")
|
||||
print(f"🔗 Source list: {response.data.source_list[:200] if response.data.source_list else 'None'}")
|
||||
|
||||
if response.research_sources:
|
||||
print(f"📚 First research source: {response.research_sources[0]}")
|
||||
print(f"📚 Research source types: {[type(s) for s in response.research_sources[:3]]}")
|
||||
|
||||
if response.data.citations:
|
||||
print(f"📝 First citation: {response.data.citations[0]}")
|
||||
else:
|
||||
print(f"❌ Post generation failed: {response.error}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error during test: {str(e)}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(test_grounding_flow())
|
||||
228
backend/test/test_grounding_integration.py
Normal file
228
backend/test/test_grounding_integration.py
Normal file
@@ -0,0 +1,228 @@
|
||||
"""
|
||||
Test script for LinkedIn grounding integration.
|
||||
|
||||
This script tests the integration of the new grounding services:
|
||||
- GoogleSearchService
|
||||
- GeminiGroundedProvider
|
||||
- CitationManager
|
||||
- ContentQualityAnalyzer
|
||||
- Enhanced LinkedInService
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
from datetime import datetime
|
||||
from loguru import logger
|
||||
|
||||
# Set up environment variables for testing
|
||||
os.environ.setdefault('GOOGLE_SEARCH_API_KEY', 'test_key')
|
||||
os.environ.setdefault('GOOGLE_SEARCH_ENGINE_ID', 'test_engine_id')
|
||||
os.environ.setdefault('GEMINI_API_KEY', 'test_gemini_key')
|
||||
|
||||
from services.linkedin_service import LinkedInService
|
||||
from models.linkedin_models import (
|
||||
LinkedInPostRequest, LinkedInArticleRequest, LinkedInCarouselRequest,
|
||||
LinkedInVideoScriptRequest, LinkedInCommentResponseRequest,
|
||||
GroundingLevel, SearchEngine, LinkedInTone, LinkedInPostType
|
||||
)
|
||||
|
||||
|
||||
async def test_grounding_integration():
|
||||
"""Test the complete grounding integration."""
|
||||
logger.info("Starting LinkedIn grounding integration test")
|
||||
|
||||
try:
|
||||
# Initialize the enhanced LinkedIn service
|
||||
linkedin_service = LinkedInService()
|
||||
logger.info("LinkedIn service initialized successfully")
|
||||
|
||||
# Test 1: Basic post generation with grounding disabled
|
||||
logger.info("\n=== Test 1: Basic Post Generation (No Grounding) ===")
|
||||
basic_request = LinkedInPostRequest(
|
||||
topic="AI in Marketing",
|
||||
industry="Marketing",
|
||||
post_type=LinkedInPostType.PROFESSIONAL,
|
||||
tone=LinkedInTone.PROFESSIONAL,
|
||||
research_enabled=False,
|
||||
grounding_level=GroundingLevel.NONE,
|
||||
include_citations=False
|
||||
)
|
||||
|
||||
basic_response = await linkedin_service.generate_linkedin_post(basic_request)
|
||||
logger.info(f"Basic post generation: {'SUCCESS' if basic_response.success else 'FAILED'}")
|
||||
if basic_response.success:
|
||||
logger.info(f"Content length: {basic_response.data.character_count}")
|
||||
logger.info(f"Grounding enabled: {basic_response.data.grounding_enabled}")
|
||||
|
||||
# Test 2: Enhanced post generation with grounding enabled
|
||||
logger.info("\n=== Test 2: Enhanced Post Generation (With Grounding) ===")
|
||||
enhanced_request = LinkedInPostRequest(
|
||||
topic="Digital Transformation in Healthcare",
|
||||
industry="Healthcare",
|
||||
post_type=LinkedInPostType.THOUGHT_LEADERSHIP,
|
||||
tone=LinkedInTone.AUTHORITATIVE,
|
||||
research_enabled=True,
|
||||
search_engine=SearchEngine.GOOGLE,
|
||||
grounding_level=GroundingLevel.ENHANCED,
|
||||
include_citations=True,
|
||||
max_length=2000
|
||||
)
|
||||
|
||||
enhanced_response = await linkedin_service.generate_linkedin_post(enhanced_request)
|
||||
logger.info(f"Enhanced post generation: {'SUCCESS' if enhanced_response.success else 'FAILED'}")
|
||||
if enhanced_response.success:
|
||||
logger.info(f"Content length: {enhanced_response.data.character_count}")
|
||||
logger.info(f"Grounding enabled: {enhanced_response.data.grounding_enabled}")
|
||||
logger.info(f"Research sources: {len(enhanced_response.research_sources)}")
|
||||
logger.info(f"Citations: {len(enhanced_response.data.citations)}")
|
||||
if enhanced_response.data.quality_metrics:
|
||||
logger.info(f"Quality score: {enhanced_response.data.quality_metrics.overall_score:.2f}")
|
||||
if enhanced_response.grounding_status:
|
||||
logger.info(f"Grounding status: {enhanced_response.grounding_status['status']}")
|
||||
|
||||
# Test 3: Article generation with grounding
|
||||
logger.info("\n=== Test 3: Article Generation (With Grounding) ===")
|
||||
article_request = LinkedInArticleRequest(
|
||||
topic="Future of Remote Work",
|
||||
industry="Technology",
|
||||
tone=LinkedInTone.EDUCATIONAL,
|
||||
research_enabled=True,
|
||||
search_engine=SearchEngine.GOOGLE,
|
||||
grounding_level=GroundingLevel.ENHANCED,
|
||||
include_citations=True,
|
||||
word_count=1500
|
||||
)
|
||||
|
||||
article_response = await linkedin_service.generate_linkedin_article(article_request)
|
||||
logger.info(f"Article generation: {'SUCCESS' if article_response.success else 'FAILED'}")
|
||||
if article_response.success:
|
||||
logger.info(f"Word count: {article_response.data.word_count}")
|
||||
logger.info(f"Grounding enabled: {article_response.data.grounding_enabled}")
|
||||
logger.info(f"Research sources: {len(article_response.research_sources)}")
|
||||
logger.info(f"Citations: {len(article_response.data.citations)}")
|
||||
|
||||
# Test 4: Carousel generation with grounding
|
||||
logger.info("\n=== Test 4: Carousel Generation (With Grounding) ===")
|
||||
carousel_request = LinkedInCarouselRequest(
|
||||
topic="Cybersecurity Best Practices",
|
||||
industry="Technology",
|
||||
tone=LinkedInTone.EDUCATIONAL,
|
||||
research_enabled=True,
|
||||
search_engine=SearchEngine.GOOGLE,
|
||||
grounding_level=GroundingLevel.ENHANCED,
|
||||
include_citations=True,
|
||||
number_of_slides=5
|
||||
)
|
||||
|
||||
carousel_response = await linkedin_service.generate_linkedin_carousel(carousel_request)
|
||||
logger.info(f"Carousel generation: {'SUCCESS' if carousel_response.success else 'FAILED'}")
|
||||
if carousel_response.success:
|
||||
logger.info(f"Number of slides: {len(carousel_response.data.slides)}")
|
||||
logger.info(f"Grounding enabled: {carousel_response.data.grounding_enabled}")
|
||||
logger.info(f"Research sources: {len(carousel_response.research_sources)}")
|
||||
|
||||
# Test 5: Video script generation with grounding
|
||||
logger.info("\n=== Test 5: Video Script Generation (With Grounding) ===")
|
||||
video_request = LinkedInVideoScriptRequest(
|
||||
topic="AI Ethics in Business",
|
||||
industry="Technology",
|
||||
tone=LinkedInTone.EDUCATIONAL,
|
||||
research_enabled=True,
|
||||
search_engine=SearchEngine.GOOGLE,
|
||||
grounding_level=GroundingLevel.ENHANCED,
|
||||
include_citations=True,
|
||||
video_duration=90
|
||||
)
|
||||
|
||||
video_response = await linkedin_service.generate_linkedin_video_script(video_request)
|
||||
logger.info(f"Video script generation: {'SUCCESS' if video_response.success else 'FAILED'}")
|
||||
if video_response.success:
|
||||
logger.info(f"Grounding enabled: {video_response.data.grounding_enabled}")
|
||||
logger.info(f"Research sources: {len(video_response.research_sources)}")
|
||||
logger.info(f"Citations: {len(video_response.data.citations)}")
|
||||
|
||||
# Test 6: Comment response generation
|
||||
logger.info("\n=== Test 6: Comment Response Generation ===")
|
||||
comment_request = LinkedInCommentResponseRequest(
|
||||
original_comment="Great insights on AI implementation!",
|
||||
post_context="Post about AI transformation in healthcare",
|
||||
industry="Healthcare",
|
||||
tone=LinkedInTone.FRIENDLY,
|
||||
response_length="medium",
|
||||
include_questions=True,
|
||||
research_enabled=False,
|
||||
grounding_level=GroundingLevel.BASIC
|
||||
)
|
||||
|
||||
comment_response = await linkedin_service.generate_linkedin_comment_response(comment_request)
|
||||
logger.info(f"Comment response generation: {'SUCCESS' if comment_response.success else 'FAILED'}")
|
||||
if comment_response.success:
|
||||
logger.info(f"Response length: {len(comment_response.response) if comment_response.response else 0}")
|
||||
logger.info(f"Grounding enabled: {comment_response.grounding_status['status'] if comment_response.grounding_status else 'N/A'}")
|
||||
|
||||
logger.info("\n=== Integration Test Summary ===")
|
||||
logger.info("All tests completed successfully!")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Integration test failed: {str(e)}")
|
||||
raise
|
||||
|
||||
|
||||
async def test_individual_services():
|
||||
"""Test individual service components."""
|
||||
logger.info("\n=== Testing Individual Service Components ===")
|
||||
|
||||
try:
|
||||
# Test Google Search Service
|
||||
from services.research import GoogleSearchService
|
||||
google_search = GoogleSearchService()
|
||||
logger.info("GoogleSearchService initialized successfully")
|
||||
|
||||
# Test Citation Manager
|
||||
from services.citation import CitationManager
|
||||
citation_manager = CitationManager()
|
||||
logger.info("CitationManager initialized successfully")
|
||||
|
||||
# Test Content Quality Analyzer
|
||||
from services.quality import ContentQualityAnalyzer
|
||||
quality_analyzer = ContentQualityAnalyzer()
|
||||
logger.info("ContentQualityAnalyzer initialized successfully")
|
||||
|
||||
# Test Gemini Grounded Provider
|
||||
from services.llm_providers.gemini_grounded_provider import GeminiGroundedProvider
|
||||
gemini_grounded = GeminiGroundedProvider()
|
||||
logger.info("GeminiGroundedProvider initialized successfully")
|
||||
|
||||
logger.info("All individual services initialized successfully!")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Service component test failed: {str(e)}")
|
||||
raise
|
||||
|
||||
|
||||
async def main():
|
||||
"""Main test function."""
|
||||
logger.info("Starting LinkedIn Grounding Integration Tests")
|
||||
logger.info(f"Test timestamp: {datetime.now().isoformat()}")
|
||||
|
||||
try:
|
||||
# Test individual services first
|
||||
await test_individual_services()
|
||||
|
||||
# Test complete integration
|
||||
await test_grounding_integration()
|
||||
|
||||
logger.info("\n🎉 All tests completed successfully!")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Test suite failed: {str(e)}")
|
||||
logger.error("Please check the error details above and ensure all services are properly configured.")
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Run the tests
|
||||
exit_code = asyncio.run(main())
|
||||
exit(exit_code)
|
||||
134
backend/test/test_hallucination_detector.py
Normal file
134
backend/test/test_hallucination_detector.py
Normal file
@@ -0,0 +1,134 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test script for the hallucination detector service.
|
||||
|
||||
This script tests the hallucination detector functionality
|
||||
without requiring the full FastAPI server to be running.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Add the backend directory to the Python path
|
||||
backend_dir = Path(__file__).parent
|
||||
sys.path.insert(0, str(backend_dir))
|
||||
|
||||
from services.hallucination_detector import HallucinationDetector
|
||||
|
||||
async def test_hallucination_detector():
|
||||
"""Test the hallucination detector with sample text."""
|
||||
|
||||
print("🧪 Testing Hallucination Detector")
|
||||
print("=" * 50)
|
||||
|
||||
# Initialize detector
|
||||
detector = HallucinationDetector()
|
||||
|
||||
# Test text with various types of claims
|
||||
test_text = """
|
||||
The Eiffel Tower is located in Paris, France. It was built in 1889 and stands 330 meters tall.
|
||||
The tower was designed by Gustave Eiffel and is one of the most visited monuments in the world.
|
||||
Our company increased sales by 25% last quarter and launched three new products.
|
||||
The weather today is sunny with a temperature of 22 degrees Celsius.
|
||||
"""
|
||||
|
||||
print(f"📝 Test Text:\n{test_text.strip()}\n")
|
||||
|
||||
try:
|
||||
# Test claim extraction
|
||||
print("🔍 Testing claim extraction...")
|
||||
claims = await detector._extract_claims(test_text)
|
||||
print(f"✅ Extracted {len(claims)} claims:")
|
||||
for i, claim in enumerate(claims, 1):
|
||||
print(f" {i}. {claim}")
|
||||
print()
|
||||
|
||||
# Test full hallucination detection
|
||||
print("🔍 Testing full hallucination detection...")
|
||||
result = await detector.detect_hallucinations(test_text)
|
||||
|
||||
print(f"✅ Analysis completed:")
|
||||
print(f" Overall Confidence: {result.overall_confidence:.2f}")
|
||||
print(f" Total Claims: {result.total_claims}")
|
||||
print(f" Supported: {result.supported_claims}")
|
||||
print(f" Refuted: {result.refuted_claims}")
|
||||
print(f" Insufficient: {result.insufficient_claims}")
|
||||
print()
|
||||
|
||||
# Display individual claims
|
||||
print("📊 Individual Claim Analysis:")
|
||||
for i, claim in enumerate(result.claims, 1):
|
||||
print(f"\n Claim {i}: {claim.text}")
|
||||
print(f" Assessment: {claim.assessment}")
|
||||
print(f" Confidence: {claim.confidence:.2f}")
|
||||
print(f" Supporting Sources: {len(claim.supporting_sources)}")
|
||||
print(f" Refuting Sources: {len(claim.refuting_sources)}")
|
||||
|
||||
if claim.supporting_sources:
|
||||
print(" Supporting Sources:")
|
||||
for j, source in enumerate(claim.supporting_sources[:2], 1): # Show first 2
|
||||
print(f" {j}. {source.get('title', 'Untitled')} (Score: {source.get('score', 0):.2f})")
|
||||
|
||||
if claim.refuting_sources:
|
||||
print(" Refuting Sources:")
|
||||
for j, source in enumerate(claim.refuting_sources[:2], 1): # Show first 2
|
||||
print(f" {j}. {source.get('title', 'Untitled')} (Score: {source.get('score', 0):.2f})")
|
||||
|
||||
print("\n✅ Test completed successfully!")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Test failed with error: {str(e)}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
async def test_health_check():
|
||||
"""Test the health check functionality."""
|
||||
|
||||
print("\n🏥 Testing Health Check")
|
||||
print("=" * 30)
|
||||
|
||||
detector = HallucinationDetector()
|
||||
|
||||
# Check API availability
|
||||
exa_available = bool(detector.exa_api_key)
|
||||
openai_available = bool(detector.openai_api_key)
|
||||
|
||||
print(f"Exa.ai API Available: {'✅' if exa_available else '❌'}")
|
||||
print(f"OpenAI API Available: {'✅' if openai_available else '❌'}")
|
||||
|
||||
if not exa_available:
|
||||
print("⚠️ Exa.ai API key not found. Set EXA_API_KEY environment variable.")
|
||||
|
||||
if not openai_available:
|
||||
print("⚠️ OpenAI API key not found. Set OPENAI_API_KEY environment variable.")
|
||||
|
||||
if exa_available and openai_available:
|
||||
print("✅ All APIs are available for full functionality.")
|
||||
elif openai_available:
|
||||
print("⚠️ Limited functionality available (claim extraction only).")
|
||||
else:
|
||||
print("❌ No APIs available. Only fallback functionality will work.")
|
||||
|
||||
def main():
|
||||
"""Main test function."""
|
||||
|
||||
print("🚀 Hallucination Detector Test Suite")
|
||||
print("=" * 50)
|
||||
|
||||
# Check environment variables
|
||||
print("🔧 Environment Check:")
|
||||
exa_key = os.getenv('EXA_API_KEY')
|
||||
openai_key = os.getenv('OPENAI_API_KEY')
|
||||
|
||||
print(f"EXA_API_KEY: {'✅ Set' if exa_key else '❌ Not set'}")
|
||||
print(f"OPENAI_API_KEY: {'✅ Set' if openai_key else '❌ Not set'}")
|
||||
print()
|
||||
|
||||
# Run tests
|
||||
asyncio.run(test_health_check())
|
||||
asyncio.run(test_hallucination_detector())
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
95
backend/test/test_image_api.py
Normal file
95
backend/test/test_image_api.py
Normal file
@@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test script for LinkedIn Image Generation API endpoints
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import aiohttp
|
||||
import json
|
||||
|
||||
async def test_image_generation_api():
|
||||
"""Test the LinkedIn image generation API endpoints"""
|
||||
|
||||
base_url = "http://localhost:8000"
|
||||
|
||||
print("🧪 Testing LinkedIn Image Generation API...")
|
||||
print("=" * 50)
|
||||
|
||||
# Test 1: Health Check
|
||||
print("\n1️⃣ Testing Health Check...")
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(f"{base_url}/api/linkedin/image-generation-health") as response:
|
||||
if response.status == 200:
|
||||
health_data = await response.json()
|
||||
print(f"✅ Health Check: {health_data['status']}")
|
||||
print(f" Services: {health_data['services']}")
|
||||
print(f" Test Prompts: {health_data['test_prompts_generated']}")
|
||||
else:
|
||||
print(f"❌ Health Check Failed: {response.status}")
|
||||
return
|
||||
|
||||
# Test 2: Generate Image Prompts
|
||||
print("\n2️⃣ Testing Image Prompt Generation...")
|
||||
prompt_data = {
|
||||
"content_type": "post",
|
||||
"topic": "AI in Marketing",
|
||||
"industry": "Technology",
|
||||
"content": "This is a test LinkedIn post about AI in marketing. It demonstrates the image generation capabilities."
|
||||
}
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.post(
|
||||
f"{base_url}/api/linkedin/generate-image-prompts",
|
||||
json=prompt_data
|
||||
) as response:
|
||||
if response.status == 200:
|
||||
prompts = await response.json()
|
||||
print(f"✅ Generated {len(prompts)} image prompts:")
|
||||
for i, prompt in enumerate(prompts, 1):
|
||||
print(f" {i}. {prompt['style']}: {prompt['description']}")
|
||||
|
||||
# Test 3: Generate Image from First Prompt
|
||||
print("\n3️⃣ Testing Image Generation...")
|
||||
image_data = {
|
||||
"prompt": prompts[0]['prompt'],
|
||||
"content_context": {
|
||||
"topic": prompt_data["topic"],
|
||||
"industry": prompt_data["industry"],
|
||||
"content_type": prompt_data["content_type"],
|
||||
"content": prompt_data["content"],
|
||||
"style": prompts[0]['style']
|
||||
},
|
||||
"aspect_ratio": "1:1"
|
||||
}
|
||||
|
||||
async with session.post(
|
||||
f"{base_url}/api/linkedin/generate-image",
|
||||
json=image_data
|
||||
) as img_response:
|
||||
if img_response.status == 200:
|
||||
result = await img_response.json()
|
||||
if result.get('success'):
|
||||
print(f"✅ Image Generated Successfully!")
|
||||
print(f" Image ID: {result.get('image_id')}")
|
||||
print(f" Style: {result.get('style')}")
|
||||
print(f" Aspect Ratio: {result.get('aspect_ratio')}")
|
||||
else:
|
||||
print(f"❌ Image Generation Failed: {result.get('error')}")
|
||||
else:
|
||||
print(f"❌ Image Generation Request Failed: {img_response.status}")
|
||||
error_text = await img_response.text()
|
||||
print(f" Error: {error_text}")
|
||||
else:
|
||||
print(f"❌ Prompt Generation Failed: {response.status}")
|
||||
error_text = await response.text()
|
||||
print(f" Error: {error_text}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("🚀 Starting LinkedIn Image Generation API Tests...")
|
||||
try:
|
||||
asyncio.run(test_image_generation_api())
|
||||
print("\n🎉 All tests completed!")
|
||||
except Exception as e:
|
||||
print(f"\n💥 Test failed with error: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
139
backend/test/test_imports.py
Normal file
139
backend/test/test_imports.py
Normal file
@@ -0,0 +1,139 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Simple test script to verify import issues are fixed.
|
||||
|
||||
This script tests that all the required services can be imported and initialized
|
||||
without import errors.
|
||||
|
||||
Usage:
|
||||
python test_imports.py
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# Add the backend directory to the Python path
|
||||
backend_dir = Path(__file__).parent
|
||||
sys.path.insert(0, str(backend_dir))
|
||||
|
||||
def test_imports():
|
||||
"""Test that all required modules can be imported."""
|
||||
print("🧪 Testing Imports...")
|
||||
|
||||
try:
|
||||
print("📦 Testing LinkedIn Models...")
|
||||
from models.linkedin_models import (
|
||||
LinkedInPostRequest, LinkedInPostResponse, PostContent, ResearchSource,
|
||||
LinkedInArticleRequest, LinkedInArticleResponse, ArticleContent,
|
||||
LinkedInCarouselRequest, LinkedInCarouselResponse, CarouselContent, CarouselSlide,
|
||||
LinkedInVideoScriptRequest, LinkedInVideoScriptResponse, VideoScript,
|
||||
LinkedInCommentResponseRequest, LinkedInCommentResponseResult,
|
||||
HashtagSuggestion, ImageSuggestion, Citation, ContentQualityMetrics,
|
||||
GroundingLevel
|
||||
)
|
||||
print("✅ LinkedIn Models imported successfully")
|
||||
except Exception as e:
|
||||
print(f"❌ LinkedIn Models import failed: {e}")
|
||||
return False
|
||||
|
||||
try:
|
||||
print("📦 Testing Research Service...")
|
||||
from services.research import GoogleSearchService
|
||||
print("✅ Research Service imported successfully")
|
||||
except Exception as e:
|
||||
print(f"❌ Research Service import failed: {e}")
|
||||
return False
|
||||
|
||||
try:
|
||||
print("📦 Testing Citation Service...")
|
||||
from services.citation import CitationManager
|
||||
print("✅ Citation Service imported successfully")
|
||||
except Exception as e:
|
||||
print(f"❌ Citation Service import failed: {e}")
|
||||
return False
|
||||
|
||||
try:
|
||||
print("📦 Testing Quality Service...")
|
||||
from services.quality import ContentQualityAnalyzer
|
||||
print("✅ Quality Service imported successfully")
|
||||
except Exception as e:
|
||||
print(f"❌ Quality Service import failed: {e}")
|
||||
return False
|
||||
|
||||
try:
|
||||
print("📦 Testing LLM Providers...")
|
||||
from services.llm_providers.gemini_provider import gemini_structured_json_response, gemini_text_response
|
||||
print("✅ LLM Providers imported successfully")
|
||||
except Exception as e:
|
||||
print(f"❌ LLM Providers import failed: {e}")
|
||||
return False
|
||||
|
||||
try:
|
||||
print("📦 Testing Gemini Grounded Provider...")
|
||||
from services.llm_providers.gemini_grounded_provider import GeminiGroundedProvider
|
||||
print("✅ Gemini Grounded Provider imported successfully")
|
||||
except Exception as e:
|
||||
print(f"❌ Gemini Grounded Provider import failed: {e}")
|
||||
return False
|
||||
|
||||
try:
|
||||
print("📦 Testing LinkedIn Service...")
|
||||
from services.linkedin_service import LinkedInService
|
||||
print("✅ LinkedIn Service imported successfully")
|
||||
except Exception as e:
|
||||
print(f"❌ LinkedIn Service import failed: {e}")
|
||||
return False
|
||||
|
||||
print("\n🎉 All imports successful!")
|
||||
return True
|
||||
|
||||
def test_service_initialization():
|
||||
"""Test that services can be initialized without errors."""
|
||||
print("\n🔧 Testing Service Initialization...")
|
||||
|
||||
try:
|
||||
print("📦 Initializing LinkedIn Service...")
|
||||
from services.linkedin_service import LinkedInService
|
||||
service = LinkedInService()
|
||||
print("✅ LinkedIn Service initialized successfully")
|
||||
|
||||
# Check which services are available
|
||||
print(f" - Google Search: {'✅' if service.google_search else '❌'}")
|
||||
print(f" - Gemini Grounded: {'✅' if service.gemini_grounded else '❌'}")
|
||||
print(f" - Citation Manager: {'✅' if service.citation_manager else '❌'}")
|
||||
print(f" - Quality Analyzer: {'✅' if service.quality_analyzer else '❌'}")
|
||||
print(f" - Fallback Provider: {'✅' if service.fallback_provider else '❌'}")
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"❌ LinkedIn Service initialization failed: {e}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
"""Main test function."""
|
||||
print("🚀 Starting Import Tests")
|
||||
print("=" * 50)
|
||||
|
||||
# Test imports
|
||||
import_success = test_imports()
|
||||
|
||||
if import_success:
|
||||
# Test service initialization
|
||||
init_success = test_service_initialization()
|
||||
|
||||
if init_success:
|
||||
print("\n🎉 SUCCESS: All tests passed!")
|
||||
print("✅ Import issues have been resolved")
|
||||
print("✅ Services can be initialized")
|
||||
print("✅ Ready for testing native grounding")
|
||||
else:
|
||||
print("\n⚠️ PARTIAL SUCCESS: Imports work but initialization failed")
|
||||
print("💡 This may be due to missing dependencies or configuration")
|
||||
else:
|
||||
print("\n❌ FAILURE: Import tests failed")
|
||||
print("💡 There are still import issues to resolve")
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
341
backend/test/test_linkedin_endpoints.py
Normal file
341
backend/test/test_linkedin_endpoints.py
Normal file
@@ -0,0 +1,341 @@
|
||||
"""
|
||||
Test script for LinkedIn content generation endpoints.
|
||||
|
||||
This script tests the LinkedIn content generation functionality
|
||||
to ensure proper integration and validation.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import time
|
||||
from typing import Dict, Any
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Add the backend directory to Python path
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
from models.linkedin_models import (
|
||||
LinkedInPostRequest, LinkedInArticleRequest, LinkedInCarouselRequest,
|
||||
LinkedInVideoScriptRequest, LinkedInCommentResponseRequest
|
||||
)
|
||||
from services.linkedin_service import linkedin_service
|
||||
from loguru import logger
|
||||
|
||||
# Configure logger
|
||||
logger.remove()
|
||||
logger.add(sys.stdout, level="INFO", format="<level>{level}</level> | {message}")
|
||||
|
||||
|
||||
async def test_post_generation():
|
||||
"""Test LinkedIn post generation."""
|
||||
logger.info("🧪 Testing LinkedIn Post Generation")
|
||||
|
||||
try:
|
||||
request = LinkedInPostRequest(
|
||||
topic="Artificial Intelligence in Healthcare",
|
||||
industry="Healthcare",
|
||||
post_type="thought_leadership",
|
||||
tone="professional",
|
||||
target_audience="Healthcare executives and AI professionals",
|
||||
key_points=["AI diagnostics", "Patient outcomes", "Cost reduction", "Implementation challenges"],
|
||||
include_hashtags=True,
|
||||
include_call_to_action=True,
|
||||
research_enabled=True,
|
||||
search_engine="metaphor",
|
||||
max_length=2000
|
||||
)
|
||||
|
||||
start_time = time.time()
|
||||
response = await linkedin_service.generate_post(request)
|
||||
duration = time.time() - start_time
|
||||
|
||||
logger.info(f"✅ Post generation completed in {duration:.2f} seconds")
|
||||
logger.info(f"Success: {response.success}")
|
||||
|
||||
if response.success and response.data:
|
||||
logger.info(f"Content length: {response.data.character_count} characters")
|
||||
logger.info(f"Hashtags generated: {len(response.data.hashtags)}")
|
||||
logger.info(f"Call-to-action: {response.data.call_to_action is not None}")
|
||||
logger.info(f"Research sources: {len(response.research_sources)}")
|
||||
|
||||
# Preview content (first 200 chars)
|
||||
content_preview = response.data.content[:200] + "..." if len(response.data.content) > 200 else response.data.content
|
||||
logger.info(f"Content preview: {content_preview}")
|
||||
else:
|
||||
logger.error(f"Post generation failed: {response.error}")
|
||||
|
||||
return response.success
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Error testing post generation: {str(e)}")
|
||||
return False
|
||||
|
||||
|
||||
async def test_article_generation():
|
||||
"""Test LinkedIn article generation."""
|
||||
logger.info("🧪 Testing LinkedIn Article Generation")
|
||||
|
||||
try:
|
||||
request = LinkedInArticleRequest(
|
||||
topic="Digital Transformation in Manufacturing",
|
||||
industry="Manufacturing",
|
||||
tone="professional",
|
||||
target_audience="Manufacturing leaders and technology professionals",
|
||||
key_sections=["Current challenges", "Technology solutions", "Implementation strategies", "Future outlook"],
|
||||
include_images=True,
|
||||
seo_optimization=True,
|
||||
research_enabled=True,
|
||||
search_engine="metaphor",
|
||||
word_count=1500
|
||||
)
|
||||
|
||||
start_time = time.time()
|
||||
response = await linkedin_service.generate_article(request)
|
||||
duration = time.time() - start_time
|
||||
|
||||
logger.info(f"✅ Article generation completed in {duration:.2f} seconds")
|
||||
logger.info(f"Success: {response.success}")
|
||||
|
||||
if response.success and response.data:
|
||||
logger.info(f"Word count: {response.data.word_count}")
|
||||
logger.info(f"Sections: {len(response.data.sections)}")
|
||||
logger.info(f"Reading time: {response.data.reading_time} minutes")
|
||||
logger.info(f"Image suggestions: {len(response.data.image_suggestions)}")
|
||||
logger.info(f"SEO metadata: {response.data.seo_metadata is not None}")
|
||||
logger.info(f"Research sources: {len(response.research_sources)}")
|
||||
|
||||
# Preview title
|
||||
logger.info(f"Article title: {response.data.title}")
|
||||
else:
|
||||
logger.error(f"Article generation failed: {response.error}")
|
||||
|
||||
return response.success
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Error testing article generation: {str(e)}")
|
||||
return False
|
||||
|
||||
|
||||
async def test_carousel_generation():
|
||||
"""Test LinkedIn carousel generation."""
|
||||
logger.info("🧪 Testing LinkedIn Carousel Generation")
|
||||
|
||||
try:
|
||||
request = LinkedInCarouselRequest(
|
||||
topic="5 Ways to Improve Team Productivity",
|
||||
industry="Business Management",
|
||||
slide_count=8,
|
||||
tone="professional",
|
||||
target_audience="Team leaders and managers",
|
||||
key_takeaways=["Clear communication", "Goal setting", "Tool optimization", "Regular feedback", "Work-life balance"],
|
||||
include_cover_slide=True,
|
||||
include_cta_slide=True,
|
||||
visual_style="modern"
|
||||
)
|
||||
|
||||
start_time = time.time()
|
||||
response = await linkedin_service.generate_carousel(request)
|
||||
duration = time.time() - start_time
|
||||
|
||||
logger.info(f"✅ Carousel generation completed in {duration:.2f} seconds")
|
||||
logger.info(f"Success: {response.success}")
|
||||
|
||||
if response.success and response.data:
|
||||
logger.info(f"Slide count: {len(response.data.slides)}")
|
||||
logger.info(f"Carousel title: {response.data.title}")
|
||||
logger.info(f"Design guidelines: {bool(response.data.design_guidelines)}")
|
||||
|
||||
# Preview first slide
|
||||
if response.data.slides:
|
||||
first_slide = response.data.slides[0]
|
||||
logger.info(f"First slide title: {first_slide.title}")
|
||||
else:
|
||||
logger.error(f"Carousel generation failed: {response.error}")
|
||||
|
||||
return response.success
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Error testing carousel generation: {str(e)}")
|
||||
return False
|
||||
|
||||
|
||||
async def test_video_script_generation():
|
||||
"""Test LinkedIn video script generation."""
|
||||
logger.info("🧪 Testing LinkedIn Video Script Generation")
|
||||
|
||||
try:
|
||||
request = LinkedInVideoScriptRequest(
|
||||
topic="Quick tips for remote team management",
|
||||
industry="Human Resources",
|
||||
video_length=90,
|
||||
tone="conversational",
|
||||
target_audience="Remote team managers",
|
||||
key_messages=["Communication tools", "Regular check-ins", "Team building", "Performance tracking"],
|
||||
include_hook=True,
|
||||
include_captions=True
|
||||
)
|
||||
|
||||
start_time = time.time()
|
||||
response = await linkedin_service.generate_video_script(request)
|
||||
duration = time.time() - start_time
|
||||
|
||||
logger.info(f"✅ Video script generation completed in {duration:.2f} seconds")
|
||||
logger.info(f"Success: {response.success}")
|
||||
|
||||
if response.success and response.data:
|
||||
logger.info(f"Hook: {bool(response.data.hook)}")
|
||||
logger.info(f"Main content scenes: {len(response.data.main_content)}")
|
||||
logger.info(f"Conclusion: {bool(response.data.conclusion)}")
|
||||
logger.info(f"Thumbnail suggestions: {len(response.data.thumbnail_suggestions)}")
|
||||
logger.info(f"Captions: {bool(response.data.captions)}")
|
||||
|
||||
# Preview hook
|
||||
if response.data.hook:
|
||||
hook_preview = response.data.hook[:100] + "..." if len(response.data.hook) > 100 else response.data.hook
|
||||
logger.info(f"Hook preview: {hook_preview}")
|
||||
else:
|
||||
logger.error(f"Video script generation failed: {response.error}")
|
||||
|
||||
return response.success
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Error testing video script generation: {str(e)}")
|
||||
return False
|
||||
|
||||
|
||||
async def test_comment_response_generation():
|
||||
"""Test LinkedIn comment response generation."""
|
||||
logger.info("🧪 Testing LinkedIn Comment Response Generation")
|
||||
|
||||
try:
|
||||
request = LinkedInCommentResponseRequest(
|
||||
original_post="Just published an article about AI transformation in healthcare. The potential for improving patient outcomes while reducing costs is incredible. Healthcare leaders need to start preparing for this shift now.",
|
||||
comment="Great insights! How do you see this affecting smaller healthcare providers who might not have the resources for large AI implementations?",
|
||||
response_type="value_add",
|
||||
tone="professional",
|
||||
include_question=True,
|
||||
brand_voice="Expert but approachable, data-driven and helpful"
|
||||
)
|
||||
|
||||
start_time = time.time()
|
||||
response = await linkedin_service.generate_comment_response(request)
|
||||
duration = time.time() - start_time
|
||||
|
||||
logger.info(f"✅ Comment response generation completed in {duration:.2f} seconds")
|
||||
logger.info(f"Success: {response.success}")
|
||||
|
||||
if response.success and response.response:
|
||||
logger.info(f"Primary response length: {len(response.response)} characters")
|
||||
logger.info(f"Alternative responses: {len(response.alternative_responses)}")
|
||||
logger.info(f"Tone analysis: {bool(response.tone_analysis)}")
|
||||
|
||||
# Preview response
|
||||
response_preview = response.response[:150] + "..." if len(response.response) > 150 else response.response
|
||||
logger.info(f"Response preview: {response_preview}")
|
||||
|
||||
if response.tone_analysis:
|
||||
logger.info(f"Detected sentiment: {response.tone_analysis.get('sentiment', 'unknown')}")
|
||||
else:
|
||||
logger.error(f"Comment response generation failed: {response.error}")
|
||||
|
||||
return response.success
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Error testing comment response generation: {str(e)}")
|
||||
return False
|
||||
|
||||
|
||||
async def test_error_handling():
|
||||
"""Test error handling with invalid requests."""
|
||||
logger.info("🧪 Testing Error Handling")
|
||||
|
||||
try:
|
||||
# Test with empty topic
|
||||
request = LinkedInPostRequest(
|
||||
topic="", # Empty topic should trigger validation error
|
||||
industry="Technology",
|
||||
)
|
||||
|
||||
response = await linkedin_service.generate_post(request)
|
||||
|
||||
# Should still handle gracefully
|
||||
if not response.success:
|
||||
logger.info("✅ Error handling working correctly for invalid input")
|
||||
return True
|
||||
else:
|
||||
logger.warning("⚠️ Expected error handling but got successful response")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Error in error handling test: {str(e)}")
|
||||
return False
|
||||
|
||||
|
||||
async def run_all_tests():
|
||||
"""Run all LinkedIn content generation tests."""
|
||||
logger.info("🚀 Starting LinkedIn Content Generation Tests")
|
||||
logger.info("=" * 60)
|
||||
|
||||
test_results = {}
|
||||
|
||||
# Run individual tests
|
||||
test_results["post_generation"] = await test_post_generation()
|
||||
logger.info("-" * 40)
|
||||
|
||||
test_results["article_generation"] = await test_article_generation()
|
||||
logger.info("-" * 40)
|
||||
|
||||
test_results["carousel_generation"] = await test_carousel_generation()
|
||||
logger.info("-" * 40)
|
||||
|
||||
test_results["video_script_generation"] = await test_video_script_generation()
|
||||
logger.info("-" * 40)
|
||||
|
||||
test_results["comment_response_generation"] = await test_comment_response_generation()
|
||||
logger.info("-" * 40)
|
||||
|
||||
test_results["error_handling"] = await test_error_handling()
|
||||
logger.info("-" * 40)
|
||||
|
||||
# Summary
|
||||
logger.info("📊 Test Results Summary")
|
||||
logger.info("=" * 60)
|
||||
|
||||
passed = sum(test_results.values())
|
||||
total = len(test_results)
|
||||
|
||||
for test_name, result in test_results.items():
|
||||
status = "✅ PASSED" if result else "❌ FAILED"
|
||||
logger.info(f"{test_name}: {status}")
|
||||
|
||||
logger.info(f"\nOverall: {passed}/{total} tests passed ({(passed/total)*100:.1f}%)")
|
||||
|
||||
if passed == total:
|
||||
logger.info("🎉 All tests passed! LinkedIn content generation is working correctly.")
|
||||
else:
|
||||
logger.warning(f"⚠️ {total - passed} test(s) failed. Please check the implementation.")
|
||||
|
||||
return passed == total
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Run the tests
|
||||
success = asyncio.run(run_all_tests())
|
||||
|
||||
if success:
|
||||
logger.info("\n✅ LinkedIn content generation migration completed successfully!")
|
||||
logger.info("The FastAPI endpoints are ready for use.")
|
||||
else:
|
||||
logger.error("\n❌ Some tests failed. Please review the implementation.")
|
||||
|
||||
# Print API endpoint information
|
||||
logger.info("\n📡 Available LinkedIn Content Generation Endpoints:")
|
||||
logger.info("- POST /api/linkedin/generate-post")
|
||||
logger.info("- POST /api/linkedin/generate-article")
|
||||
logger.info("- POST /api/linkedin/generate-carousel")
|
||||
logger.info("- POST /api/linkedin/generate-video-script")
|
||||
logger.info("- POST /api/linkedin/generate-comment-response")
|
||||
logger.info("- GET /api/linkedin/health")
|
||||
logger.info("- GET /api/linkedin/content-types")
|
||||
logger.info("- GET /api/linkedin/usage-stats")
|
||||
191
backend/test/test_linkedin_image_infrastructure.py
Normal file
191
backend/test/test_linkedin_image_infrastructure.py
Normal file
@@ -0,0 +1,191 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test Script for LinkedIn Image Generation Infrastructure
|
||||
|
||||
This script tests the basic functionality of the LinkedIn image generation services
|
||||
to ensure they are properly initialized and can perform basic operations.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# Add the backend directory to the Python path
|
||||
backend_path = Path(__file__).parent
|
||||
sys.path.insert(0, str(backend_path))
|
||||
|
||||
from loguru import logger
|
||||
|
||||
# Configure logging
|
||||
logger.remove()
|
||||
logger.add(sys.stdout, colorize=True, format="<level>{level}</level>| {message}")
|
||||
|
||||
|
||||
async def test_linkedin_image_infrastructure():
|
||||
"""Test the LinkedIn image generation infrastructure."""
|
||||
|
||||
logger.info("🧪 Testing LinkedIn Image Generation Infrastructure")
|
||||
logger.info("=" * 60)
|
||||
|
||||
try:
|
||||
# Test 1: Import LinkedIn Image Services
|
||||
logger.info("📦 Test 1: Importing LinkedIn Image Services...")
|
||||
|
||||
from services.linkedin.image_generation import (
|
||||
LinkedInImageGenerator,
|
||||
LinkedInImageEditor,
|
||||
LinkedInImageStorage
|
||||
)
|
||||
from services.linkedin.image_prompts import LinkedInPromptGenerator
|
||||
|
||||
logger.success("✅ All LinkedIn image services imported successfully")
|
||||
|
||||
# Test 2: Initialize Services
|
||||
logger.info("🔧 Test 2: Initializing LinkedIn Image Services...")
|
||||
|
||||
# Initialize services (without API keys for testing)
|
||||
image_generator = LinkedInImageGenerator()
|
||||
image_editor = LinkedInImageEditor()
|
||||
image_storage = LinkedInImageStorage()
|
||||
prompt_generator = LinkedInPromptGenerator()
|
||||
|
||||
logger.success("✅ All LinkedIn image services initialized successfully")
|
||||
|
||||
# Test 3: Test Prompt Generation (without API calls)
|
||||
logger.info("📝 Test 3: Testing Prompt Generation Logic...")
|
||||
|
||||
# Test content context
|
||||
test_content = {
|
||||
'topic': 'AI in Marketing',
|
||||
'industry': 'Technology',
|
||||
'content_type': 'post',
|
||||
'content': 'Exploring how artificial intelligence is transforming modern marketing strategies.'
|
||||
}
|
||||
|
||||
# Test fallback prompt generation
|
||||
fallback_prompts = prompt_generator._get_fallback_prompts(test_content, "1:1")
|
||||
|
||||
if len(fallback_prompts) == 3:
|
||||
logger.success(f"✅ Fallback prompt generation working: {len(fallback_prompts)} prompts created")
|
||||
|
||||
for i, prompt in enumerate(fallback_prompts):
|
||||
logger.info(f" Prompt {i+1}: {prompt['style']} - {prompt['description']}")
|
||||
else:
|
||||
logger.error(f"❌ Fallback prompt generation failed: expected 3, got {len(fallback_prompts)}")
|
||||
|
||||
# Test 4: Test Image Storage Directory Creation
|
||||
logger.info("📁 Test 4: Testing Image Storage Directory Creation...")
|
||||
|
||||
# Check if storage directories were created
|
||||
storage_path = image_storage.base_storage_path
|
||||
if storage_path.exists():
|
||||
logger.success(f"✅ Storage base directory created: {storage_path}")
|
||||
|
||||
# Check subdirectories
|
||||
for subdir in ['images', 'metadata', 'temp']:
|
||||
subdir_path = storage_path / subdir
|
||||
if subdir_path.exists():
|
||||
logger.info(f" ✅ {subdir} directory exists: {subdir_path}")
|
||||
else:
|
||||
logger.warning(f" ⚠️ {subdir} directory missing: {subdir_path}")
|
||||
else:
|
||||
logger.error(f"❌ Storage base directory not created: {storage_path}")
|
||||
|
||||
# Test 5: Test Service Methods
|
||||
logger.info("⚙️ Test 5: Testing Service Method Signatures...")
|
||||
|
||||
# Test image generator methods
|
||||
if hasattr(image_generator, 'generate_image'):
|
||||
logger.success("✅ LinkedInImageGenerator.generate_image method exists")
|
||||
else:
|
||||
logger.error("❌ LinkedInImageGenerator.generate_image method missing")
|
||||
|
||||
if hasattr(image_editor, 'edit_image_conversationally'):
|
||||
logger.success("✅ LinkedInImageEditor.edit_image_conversationally method exists")
|
||||
else:
|
||||
logger.error("❌ LinkedInImageEditor.edit_image_conversationally method missing")
|
||||
|
||||
if hasattr(image_storage, 'store_image'):
|
||||
logger.success("✅ LinkedInImageStorage.store_image method exists")
|
||||
else:
|
||||
logger.error("❌ LinkedInImageStorage.store_image method missing")
|
||||
|
||||
if hasattr(prompt_generator, 'generate_three_prompts'):
|
||||
logger.success("✅ LinkedInPromptGenerator.generate_three_prompts method exists")
|
||||
else:
|
||||
logger.error("❌ LinkedInPromptGenerator.generate_three_prompts method missing")
|
||||
|
||||
# Test 6: Test Prompt Enhancement
|
||||
logger.info("🎨 Test 6: Testing Prompt Enhancement Logic...")
|
||||
|
||||
test_prompt = {
|
||||
'style': 'Professional',
|
||||
'prompt': 'Create a business image',
|
||||
'description': 'Professional style'
|
||||
}
|
||||
|
||||
enhanced_prompt = prompt_generator._enhance_prompt_for_linkedin(
|
||||
test_prompt, test_content, "1:1", 0
|
||||
)
|
||||
|
||||
if enhanced_prompt and 'enhanced_at' in enhanced_prompt:
|
||||
logger.success("✅ Prompt enhancement working")
|
||||
logger.info(f" Enhanced prompt length: {len(enhanced_prompt['prompt'])} characters")
|
||||
else:
|
||||
logger.error("❌ Prompt enhancement failed")
|
||||
|
||||
# Test 7: Test Image Validation Logic
|
||||
logger.info("🔍 Test 7: Testing Image Validation Logic...")
|
||||
|
||||
# Test aspect ratio validation
|
||||
valid_ratios = [(1024, 1024), (1600, 900), (1200, 1600)]
|
||||
invalid_ratios = [(500, 500), (2000, 500)]
|
||||
|
||||
for width, height in valid_ratios:
|
||||
if image_generator._is_aspect_ratio_suitable(width, height):
|
||||
logger.info(f" ✅ Valid ratio {width}:{height} correctly identified")
|
||||
else:
|
||||
logger.warning(f" ⚠️ Valid ratio {width}:{height} incorrectly rejected")
|
||||
|
||||
for width, height in invalid_ratios:
|
||||
if not image_generator._is_aspect_ratio_suitable(width, height):
|
||||
logger.info(f" ✅ Invalid ratio {width}:{height} correctly rejected")
|
||||
else:
|
||||
logger.warning(f" ⚠️ Invalid ratio {width}:{height} incorrectly accepted")
|
||||
|
||||
logger.info("=" * 60)
|
||||
logger.success("🎉 LinkedIn Image Generation Infrastructure Test Completed Successfully!")
|
||||
|
||||
return True
|
||||
|
||||
except ImportError as e:
|
||||
logger.error(f"❌ Import Error: {e}")
|
||||
logger.error("This usually means there's an issue with the module structure or dependencies")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Test Failed: {e}")
|
||||
logger.error(f"Error type: {type(e).__name__}")
|
||||
import traceback
|
||||
logger.error(f"Traceback: {traceback.format_exc()}")
|
||||
return False
|
||||
|
||||
|
||||
async def main():
|
||||
"""Main test function."""
|
||||
logger.info("🚀 Starting LinkedIn Image Generation Infrastructure Tests")
|
||||
|
||||
success = await test_linkedin_image_infrastructure()
|
||||
|
||||
if success:
|
||||
logger.success("✅ All tests passed! The infrastructure is ready for use.")
|
||||
sys.exit(0)
|
||||
else:
|
||||
logger.error("❌ Some tests failed. Please check the errors above.")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Run the async test
|
||||
asyncio.run(main())
|
||||
105
backend/test/test_linkedin_service.py
Normal file
105
backend/test/test_linkedin_service.py
Normal file
@@ -0,0 +1,105 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test script for LinkedIn service functionality.
|
||||
|
||||
This script tests that the LinkedIn service can be initialized and
|
||||
basic functionality works without errors.
|
||||
|
||||
Usage:
|
||||
python test_linkedin_service.py
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# Add the backend directory to the Python path
|
||||
backend_dir = Path(__file__).parent
|
||||
sys.path.insert(0, str(backend_dir))
|
||||
|
||||
from loguru import logger
|
||||
from models.linkedin_models import LinkedInPostRequest, GroundingLevel
|
||||
from services.linkedin_service import LinkedInService
|
||||
|
||||
|
||||
async def test_linkedin_service():
|
||||
"""Test the LinkedIn service functionality."""
|
||||
try:
|
||||
logger.info("🧪 Testing LinkedIn Service Functionality")
|
||||
|
||||
# Initialize the service
|
||||
logger.info("📦 Initializing LinkedIn Service...")
|
||||
service = LinkedInService()
|
||||
logger.info("✅ LinkedIn Service initialized successfully")
|
||||
|
||||
# Create a test request
|
||||
test_request = LinkedInPostRequest(
|
||||
topic="AI in Marketing",
|
||||
industry="Technology",
|
||||
tone="professional",
|
||||
max_length=500,
|
||||
target_audience="Marketing professionals",
|
||||
key_points=["AI automation", "Personalization", "ROI improvement"],
|
||||
research_enabled=True,
|
||||
search_engine="google",
|
||||
grounding_level=GroundingLevel.BASIC,
|
||||
include_citations=True
|
||||
)
|
||||
|
||||
logger.info("📝 Testing LinkedIn Post Generation...")
|
||||
|
||||
# Test post generation
|
||||
response = await service.generate_linkedin_post(test_request)
|
||||
|
||||
if response.success:
|
||||
logger.info("✅ LinkedIn post generation successful")
|
||||
logger.info(f"📊 Content length: {len(response.data.content)} characters")
|
||||
logger.info(f"🔗 Sources: {len(response.research_sources)}")
|
||||
logger.info(f"📚 Citations: {len(response.data.citations)}")
|
||||
logger.info(f"🏆 Quality score: {response.data.quality_metrics.overall_score if response.data.quality_metrics else 'N/A'}")
|
||||
|
||||
# Display a snippet of the generated content
|
||||
content_preview = response.data.content[:200] + "..." if len(response.data.content) > 200 else response.data.content
|
||||
logger.info(f"📄 Content preview: {content_preview}")
|
||||
|
||||
else:
|
||||
logger.error(f"❌ LinkedIn post generation failed: {response.error}")
|
||||
return False
|
||||
|
||||
logger.info("🎉 LinkedIn service test completed successfully!")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ LinkedIn service test failed: {str(e)}")
|
||||
return False
|
||||
|
||||
|
||||
async def main():
|
||||
"""Main test function."""
|
||||
logger.info("🚀 Starting LinkedIn Service Test")
|
||||
logger.info("=" * 50)
|
||||
|
||||
success = await test_linkedin_service()
|
||||
|
||||
if success:
|
||||
logger.info("\n🎉 SUCCESS: LinkedIn service is working correctly!")
|
||||
logger.info("✅ Service initialization successful")
|
||||
logger.info("✅ Post generation working")
|
||||
logger.info("✅ Ready for production use")
|
||||
else:
|
||||
logger.error("\n❌ FAILURE: LinkedIn service test failed")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Configure logging
|
||||
logger.remove()
|
||||
logger.add(
|
||||
sys.stderr,
|
||||
format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>",
|
||||
level="INFO"
|
||||
)
|
||||
|
||||
# Run the test
|
||||
asyncio.run(main())
|
||||
239
backend/test/test_native_grounding.py
Normal file
239
backend/test/test_native_grounding.py
Normal file
@@ -0,0 +1,239 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test script for native Google Search grounding implementation.
|
||||
|
||||
This script tests the new GeminiGroundedProvider that uses native Google Search
|
||||
grounding instead of custom search implementation.
|
||||
|
||||
Usage:
|
||||
python test_native_grounding.py
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Add the backend directory to the Python path
|
||||
backend_dir = Path(__file__).parent
|
||||
sys.path.insert(0, str(backend_dir))
|
||||
|
||||
from loguru import logger
|
||||
from services.llm_providers.gemini_grounded_provider import GeminiGroundedProvider
|
||||
|
||||
|
||||
async def test_native_grounding():
|
||||
"""Test the native Google Search grounding functionality."""
|
||||
try:
|
||||
logger.info("🧪 Testing Native Google Search Grounding")
|
||||
|
||||
# Check if GEMINI_API_KEY is set
|
||||
if not os.getenv('GEMINI_API_KEY'):
|
||||
logger.error("❌ GEMINI_API_KEY environment variable not set")
|
||||
logger.info("Please set GEMINI_API_KEY to test native grounding")
|
||||
return False
|
||||
|
||||
# Initialize the grounded provider
|
||||
logger.info("🔧 Initializing Gemini Grounded Provider...")
|
||||
provider = GeminiGroundedProvider()
|
||||
logger.info("✅ Provider initialized successfully")
|
||||
|
||||
# Test 1: Basic grounded content generation
|
||||
logger.info("\n📝 Test 1: Basic LinkedIn Post Generation")
|
||||
test_prompt = "Write a professional LinkedIn post about the latest AI trends in 2025"
|
||||
|
||||
result = await provider.generate_grounded_content(
|
||||
prompt=test_prompt,
|
||||
content_type="linkedin_post",
|
||||
temperature=0.7,
|
||||
max_tokens=500
|
||||
)
|
||||
|
||||
if result and 'content' in result:
|
||||
logger.info("✅ Content generated successfully")
|
||||
logger.info(f"📊 Content length: {len(result['content'])} characters")
|
||||
logger.info(f"🔗 Sources found: {len(result.get('sources', []))}")
|
||||
logger.info(f"📚 Citations found: {len(result.get('citations', []))}")
|
||||
|
||||
# Display the generated content
|
||||
logger.info("\n📄 Generated Content:")
|
||||
logger.info("-" * 50)
|
||||
logger.info(result['content'][:500] + "..." if len(result['content']) > 500 else result['content'])
|
||||
logger.info("-" * 50)
|
||||
|
||||
# Display sources if available
|
||||
if result.get('sources'):
|
||||
logger.info("\n🔗 Sources:")
|
||||
for i, source in enumerate(result['sources']):
|
||||
logger.info(f" {i+1}. {source.get('title', 'Unknown')}")
|
||||
logger.info(f" URL: {source.get('url', 'N/A')}")
|
||||
|
||||
# Display search queries if available
|
||||
if result.get('search_queries'):
|
||||
logger.info(f"\n🔍 Search Queries Used: {result['search_queries']}")
|
||||
|
||||
# Display grounding metadata info
|
||||
if result.get('grounding_metadata'):
|
||||
logger.info("✅ Grounding metadata found")
|
||||
else:
|
||||
logger.warning("⚠️ No grounding metadata found")
|
||||
|
||||
else:
|
||||
logger.error("❌ Content generation failed")
|
||||
if 'error' in result:
|
||||
logger.error(f"Error: {result['error']}")
|
||||
return False
|
||||
|
||||
# Test 2: Article generation
|
||||
logger.info("\n📝 Test 2: LinkedIn Article Generation")
|
||||
article_prompt = "Create a comprehensive article about sustainable business practices in tech companies"
|
||||
|
||||
article_result = await provider.generate_grounded_content(
|
||||
prompt=article_prompt,
|
||||
content_type="linkedin_article",
|
||||
temperature=0.7,
|
||||
max_tokens=1000
|
||||
)
|
||||
|
||||
if article_result and 'content' in article_result:
|
||||
logger.info("✅ Article generated successfully")
|
||||
logger.info(f"📊 Article length: {len(article_result['content'])} characters")
|
||||
logger.info(f"🔗 Sources: {len(article_result.get('sources', []))}")
|
||||
|
||||
# Check for article-specific processing
|
||||
if 'title' in article_result:
|
||||
logger.info(f"📰 Article title: {article_result['title']}")
|
||||
if 'word_count' in article_result:
|
||||
logger.info(f"📊 Word count: {article_result['word_count']}")
|
||||
|
||||
else:
|
||||
logger.error("❌ Article generation failed")
|
||||
return False
|
||||
|
||||
# Test 3: Content quality assessment
|
||||
logger.info("\n📝 Test 3: Content Quality Assessment")
|
||||
if result.get('content') and result.get('sources'):
|
||||
quality_metrics = provider.assess_content_quality(
|
||||
content=result['content'],
|
||||
sources=result['sources']
|
||||
)
|
||||
|
||||
logger.info("✅ Quality assessment completed")
|
||||
logger.info(f"📊 Overall score: {quality_metrics.get('overall_score', 'N/A')}")
|
||||
logger.info(f"🔗 Source coverage: {quality_metrics.get('source_coverage', 'N/A')}")
|
||||
logger.info(f"🎯 Tone score: {quality_metrics.get('tone_score', 'N/A')}")
|
||||
logger.info(f"📝 Word count: {quality_metrics.get('word_count', 'N/A')}")
|
||||
logger.info(f"🏆 Quality level: {quality_metrics.get('quality_level', 'N/A')}")
|
||||
|
||||
# Test 4: Citation extraction
|
||||
logger.info("\n📝 Test 4: Citation Extraction")
|
||||
if result.get('content'):
|
||||
citations = provider.extract_citations(result['content'])
|
||||
logger.info(f"✅ Extracted {len(citations)} citations")
|
||||
|
||||
for i, citation in enumerate(citations):
|
||||
logger.info(f" Citation {i+1}: {citation.get('reference', 'Unknown')}")
|
||||
|
||||
logger.info("\n🎉 All tests completed successfully!")
|
||||
return True
|
||||
|
||||
except ImportError as e:
|
||||
logger.error(f"❌ Import error: {str(e)}")
|
||||
logger.info("💡 Make sure to install required dependencies:")
|
||||
logger.info(" pip install google-genai loguru")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Test failed with error: {str(e)}")
|
||||
return False
|
||||
|
||||
|
||||
async def test_individual_components():
|
||||
"""Test individual components of the native grounding system."""
|
||||
try:
|
||||
logger.info("🔧 Testing Individual Components")
|
||||
|
||||
# Test 1: Provider initialization
|
||||
logger.info("\n📋 Test 1: Provider Initialization")
|
||||
if not os.getenv('GEMINI_API_KEY'):
|
||||
logger.warning("⚠️ Skipping provider test - no API key")
|
||||
return False
|
||||
|
||||
provider = GeminiGroundedProvider()
|
||||
logger.info("✅ Provider initialized successfully")
|
||||
|
||||
# Test 2: Prompt building
|
||||
logger.info("\n📋 Test 2: Prompt Building")
|
||||
test_prompt = "Test prompt for LinkedIn post"
|
||||
grounded_prompt = provider._build_grounded_prompt(test_prompt, "linkedin_post")
|
||||
|
||||
if grounded_prompt and len(grounded_prompt) > len(test_prompt):
|
||||
logger.info("✅ Grounded prompt built successfully")
|
||||
logger.info(f"📊 Original length: {len(test_prompt)}")
|
||||
logger.info(f"📊 Enhanced length: {len(grounded_prompt)}")
|
||||
else:
|
||||
logger.error("❌ Prompt building failed")
|
||||
return False
|
||||
|
||||
# Test 3: Content processing methods
|
||||
logger.info("\n📋 Test 3: Content Processing Methods")
|
||||
|
||||
# Test post processing
|
||||
test_content = "This is a test LinkedIn post #AI #Technology"
|
||||
post_processing = provider._process_post_content(test_content)
|
||||
if post_processing:
|
||||
logger.info("✅ Post processing works")
|
||||
logger.info(f"🔖 Hashtags found: {len(post_processing.get('hashtags', []))}")
|
||||
|
||||
# Test article processing
|
||||
test_article = "# Test Article\n\nThis is test content for an article."
|
||||
article_processing = provider._process_article_content(test_article)
|
||||
if article_processing:
|
||||
logger.info("✅ Article processing works")
|
||||
logger.info(f"📊 Word count: {article_processing.get('word_count', 'N/A')}")
|
||||
|
||||
logger.info("✅ All component tests passed")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Component test failed: {str(e)}")
|
||||
return False
|
||||
|
||||
|
||||
async def main():
|
||||
"""Main test function."""
|
||||
logger.info("🚀 Starting Native Grounding Tests")
|
||||
logger.info("=" * 60)
|
||||
|
||||
# Test individual components first
|
||||
component_success = await test_individual_components()
|
||||
|
||||
if component_success:
|
||||
# Test the full integration
|
||||
integration_success = await test_native_grounding()
|
||||
|
||||
if integration_success:
|
||||
logger.info("\n🎉 SUCCESS: All tests passed!")
|
||||
logger.info("✅ Native Google Search grounding is working correctly")
|
||||
logger.info("✅ Gemini API integration successful")
|
||||
logger.info("✅ Grounding metadata processing working")
|
||||
logger.info("✅ Content generation with sources successful")
|
||||
else:
|
||||
logger.error("\n❌ FAILURE: Integration tests failed")
|
||||
sys.exit(1)
|
||||
else:
|
||||
logger.error("\n❌ FAILURE: Component tests failed")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Configure logging
|
||||
logger.remove()
|
||||
logger.add(
|
||||
sys.stderr,
|
||||
format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>",
|
||||
level="INFO"
|
||||
)
|
||||
|
||||
# Run the tests
|
||||
asyncio.run(main())
|
||||
106
backend/test/test_progress_endpoint.py
Normal file
106
backend/test/test_progress_endpoint.py
Normal file
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test script to verify the calendar generation progress endpoint.
|
||||
This script tests the progress endpoint to ensure it returns the correct data structure.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
# Add the current directory to the Python path
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
def test_progress_endpoint():
|
||||
"""Test the progress endpoint with a mock session."""
|
||||
try:
|
||||
from api.content_planning.services.calendar_generation_service import CalendarGenerationService
|
||||
|
||||
print("🧪 Testing Progress Endpoint")
|
||||
print("=" * 50)
|
||||
|
||||
# Initialize service
|
||||
service = CalendarGenerationService()
|
||||
|
||||
# Create a test session
|
||||
session_id = f"test-session-{int(datetime.now().timestamp())}"
|
||||
test_request_data = {
|
||||
"user_id": 1,
|
||||
"strategy_id": 1,
|
||||
"calendar_type": "monthly",
|
||||
"industry": "technology",
|
||||
"business_size": "sme"
|
||||
}
|
||||
|
||||
print(f"📋 Creating test session: {session_id}")
|
||||
|
||||
# Initialize session
|
||||
success = service.initialize_orchestrator_session(session_id, test_request_data)
|
||||
if not success:
|
||||
print("❌ Failed to initialize session")
|
||||
return False
|
||||
|
||||
print("✅ Session initialized successfully")
|
||||
|
||||
# Test progress retrieval
|
||||
print(f"🔍 Testing progress retrieval for session: {session_id}")
|
||||
progress = service.get_orchestrator_progress(session_id)
|
||||
|
||||
if not progress:
|
||||
print("❌ No progress data returned")
|
||||
return False
|
||||
|
||||
print("✅ Progress data retrieved successfully")
|
||||
print(f"📊 Progress data structure:")
|
||||
print(json.dumps(progress, indent=2, default=str))
|
||||
|
||||
# Verify required fields
|
||||
required_fields = [
|
||||
"status", "current_step", "step_progress", "overall_progress",
|
||||
"step_results", "quality_scores", "errors", "warnings"
|
||||
]
|
||||
|
||||
missing_fields = [field for field in required_fields if field not in progress]
|
||||
if missing_fields:
|
||||
print(f"❌ Missing required fields: {missing_fields}")
|
||||
return False
|
||||
|
||||
print("✅ All required fields present")
|
||||
|
||||
# Test data types
|
||||
if not isinstance(progress["current_step"], int):
|
||||
print("❌ current_step should be int")
|
||||
return False
|
||||
|
||||
if not isinstance(progress["step_progress"], (int, float)):
|
||||
print("❌ step_progress should be numeric")
|
||||
return False
|
||||
|
||||
if not isinstance(progress["overall_progress"], (int, float)):
|
||||
print("❌ overall_progress should be numeric")
|
||||
return False
|
||||
|
||||
print("✅ All data types correct")
|
||||
|
||||
# Test quality scores
|
||||
quality_scores = progress["quality_scores"]
|
||||
if not isinstance(quality_scores, dict):
|
||||
print("❌ quality_scores should be dict")
|
||||
return False
|
||||
|
||||
print("✅ Quality scores structure correct")
|
||||
|
||||
print("\n🎉 All tests passed! Progress endpoint is working correctly.")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Test failed with error: {str(e)}")
|
||||
import traceback
|
||||
print(f"📋 Traceback: {traceback.format_exc()}")
|
||||
return False
|
||||
|
||||
if __name__ == "__main__":
|
||||
success = test_progress_endpoint()
|
||||
sys.exit(0 if success else 1)
|
||||
304
backend/test/test_real_database_integration.py
Normal file
304
backend/test/test_real_database_integration.py
Normal file
@@ -0,0 +1,304 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Real Database Integration Test for Steps 1-8
|
||||
|
||||
This script tests the calendar generation framework with real database services,
|
||||
replacing all mock data with actual database operations.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
from typing import Dict, Any
|
||||
from loguru import logger
|
||||
|
||||
# Add the backend directory to the path
|
||||
backend_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
if backend_dir not in sys.path:
|
||||
sys.path.insert(0, backend_dir)
|
||||
|
||||
# Add the services directory to the path
|
||||
services_dir = os.path.join(backend_dir, "services")
|
||||
if services_dir not in sys.path:
|
||||
sys.path.insert(0, services_dir)
|
||||
|
||||
async def test_real_database_integration():
|
||||
"""Test Steps 1-8 with real database services."""
|
||||
|
||||
try:
|
||||
logger.info("🚀 Starting real database integration test")
|
||||
|
||||
# Initialize database
|
||||
logger.info("🗄️ Initializing database connection")
|
||||
from services.database import init_database, get_db_session
|
||||
|
||||
try:
|
||||
init_database()
|
||||
logger.info("✅ Database initialized successfully")
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Database initialization failed: {str(e)}")
|
||||
return False
|
||||
|
||||
# Get database session
|
||||
db_session = get_db_session()
|
||||
if not db_session:
|
||||
logger.error("❌ Failed to get database session")
|
||||
return False
|
||||
|
||||
logger.info("✅ Database session created successfully")
|
||||
|
||||
# Test data
|
||||
test_context = {
|
||||
"user_id": 1,
|
||||
"strategy_id": 1,
|
||||
"calendar_duration": 7,
|
||||
"posting_preferences": {
|
||||
"posting_frequency": "daily",
|
||||
"preferred_days": ["monday", "wednesday", "friday"],
|
||||
"preferred_times": ["09:00", "12:00", "15:00"],
|
||||
"content_per_day": 2
|
||||
}
|
||||
}
|
||||
|
||||
# Create test data in database
|
||||
logger.info("📝 Creating test data in database")
|
||||
await create_test_data(db_session, test_context)
|
||||
|
||||
# Test Step 1: Content Strategy Analysis with Real Database
|
||||
logger.info("📋 Testing Step 1: Content Strategy Analysis (Real Database)")
|
||||
try:
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.steps.phase1.phase1_steps import ContentStrategyAnalysisStep
|
||||
from services.calendar_generation_datasource_framework.data_processing.strategy_data import StrategyDataProcessor
|
||||
from services.content_planning_db import ContentPlanningDBService
|
||||
|
||||
# Create real database service
|
||||
content_planning_db = ContentPlanningDBService(db_session)
|
||||
|
||||
# Create strategy processor with real database service
|
||||
strategy_processor = StrategyDataProcessor()
|
||||
strategy_processor.content_planning_db_service = content_planning_db
|
||||
|
||||
step1 = ContentStrategyAnalysisStep()
|
||||
step1.strategy_processor = strategy_processor
|
||||
|
||||
result1 = await step1.execute(test_context)
|
||||
logger.info(f"✅ Step 1 completed: {result1.get('status')}")
|
||||
logger.info(f" Quality Score: {result1.get('quality_score')}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Step 1 failed: {str(e)}")
|
||||
return False
|
||||
|
||||
# Test Step 2: Gap Analysis with Real Database
|
||||
logger.info("📋 Testing Step 2: Gap Analysis (Real Database)")
|
||||
try:
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.steps.phase1.phase1_steps import GapAnalysisStep
|
||||
from services.calendar_generation_datasource_framework.data_processing.gap_analysis_data import GapAnalysisDataProcessor
|
||||
|
||||
# Create gap processor with real database service
|
||||
gap_processor = GapAnalysisDataProcessor()
|
||||
gap_processor.content_planning_db_service = content_planning_db
|
||||
|
||||
step2 = GapAnalysisStep()
|
||||
step2.gap_processor = gap_processor
|
||||
|
||||
result2 = await step2.execute(test_context)
|
||||
logger.info(f"✅ Step 2 completed: {result2.get('status')}")
|
||||
logger.info(f" Quality Score: {result2.get('quality_score')}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Step 2 failed: {str(e)}")
|
||||
return False
|
||||
|
||||
# Test Step 3: Audience & Platform Strategy with Real Database
|
||||
logger.info("📋 Testing Step 3: Audience & Platform Strategy (Real Database)")
|
||||
try:
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.steps.phase1.phase1_steps import AudiencePlatformStrategyStep
|
||||
from services.calendar_generation_datasource_framework.data_processing.comprehensive_user_data import ComprehensiveUserDataProcessor
|
||||
|
||||
# Create comprehensive processor with real database service
|
||||
comprehensive_processor = ComprehensiveUserDataProcessor(db_session)
|
||||
comprehensive_processor.content_planning_db_service = content_planning_db
|
||||
|
||||
step3 = AudiencePlatformStrategyStep()
|
||||
step3.comprehensive_processor = comprehensive_processor
|
||||
|
||||
result3 = await step3.execute(test_context)
|
||||
logger.info(f"✅ Step 3 completed: {result3.get('status')}")
|
||||
logger.info(f" Quality Score: {result3.get('quality_score')}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Step 3 failed: {str(e)}")
|
||||
return False
|
||||
|
||||
# Test Steps 4-8 with Real Database
|
||||
logger.info("📋 Testing Steps 4-8: Calendar Framework to Daily Content Planning (Real Database)")
|
||||
try:
|
||||
# Test Step 4: Calendar Framework
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.steps.phase2.step4_implementation import CalendarFrameworkStep
|
||||
step4 = CalendarFrameworkStep()
|
||||
result4 = await step4.execute(test_context)
|
||||
logger.info(f"✅ Step 4 completed: {result4.get('status')}")
|
||||
|
||||
# Test Step 5: Content Pillar Distribution
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.steps.phase2.step5_implementation import ContentPillarDistributionStep
|
||||
step5 = ContentPillarDistributionStep()
|
||||
result5 = await step5.execute(test_context)
|
||||
logger.info(f"✅ Step 5 completed: {result5.get('status')}")
|
||||
|
||||
# Test Step 6: Platform-Specific Strategy
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.steps.phase2.step6_implementation import PlatformSpecificStrategyStep
|
||||
step6 = PlatformSpecificStrategyStep()
|
||||
result6 = await step6.execute(test_context)
|
||||
logger.info(f"✅ Step 6 completed: {result6.get('status')}")
|
||||
|
||||
# Test Step 7: Weekly Theme Development
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.steps.phase3.step7_implementation import WeeklyThemeDevelopmentStep
|
||||
step7 = WeeklyThemeDevelopmentStep()
|
||||
result7 = await step7.execute(test_context)
|
||||
logger.info(f"✅ Step 7 completed: {result7.get('status')}")
|
||||
|
||||
# Test Step 8: Daily Content Planning
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.steps.phase3.step8_implementation import DailyContentPlanningStep
|
||||
step8 = DailyContentPlanningStep()
|
||||
result8 = await step8.execute(test_context)
|
||||
logger.info(f"✅ Step 8 completed: {result8.get('status')}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Steps 4-8 failed: {str(e)}")
|
||||
return False
|
||||
|
||||
# Clean up test data
|
||||
logger.info("🧹 Cleaning up test data")
|
||||
await cleanup_test_data(db_session, test_context)
|
||||
|
||||
# Close database session
|
||||
db_session.close()
|
||||
|
||||
logger.info("🎉 All Steps 1-8 completed successfully with real database!")
|
||||
logger.info("📝 Real database integration working perfectly!")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Test failed with error: {str(e)}")
|
||||
return False
|
||||
|
||||
async def create_test_data(db_session, test_context: Dict[str, Any]):
|
||||
"""Create test data in the database."""
|
||||
try:
|
||||
from services.content_planning_db import ContentPlanningDBService
|
||||
from models.content_planning import ContentStrategy, ContentGapAnalysis
|
||||
|
||||
db_service = ContentPlanningDBService(db_session)
|
||||
|
||||
# Create test content strategy
|
||||
strategy_data = {
|
||||
"user_id": test_context["user_id"],
|
||||
"name": "Test Strategy - Real Database",
|
||||
"industry": "technology",
|
||||
"target_audience": {
|
||||
"primary": "Tech professionals",
|
||||
"secondary": "Business leaders",
|
||||
"demographics": {"age_range": "25-45", "location": "Global"}
|
||||
},
|
||||
"content_pillars": [
|
||||
"AI and Machine Learning",
|
||||
"Digital Transformation",
|
||||
"Innovation and Technology Trends",
|
||||
"Business Strategy and Growth"
|
||||
],
|
||||
"ai_recommendations": {
|
||||
"strategic_insights": [
|
||||
"Focus on deep-dive technical content",
|
||||
"Emphasize practical implementation guides",
|
||||
"Highlight ROI and business impact"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
strategy = await db_service.create_content_strategy(strategy_data)
|
||||
if strategy:
|
||||
logger.info(f"✅ Created test strategy: {strategy.id}")
|
||||
test_context["strategy_id"] = strategy.id
|
||||
|
||||
# Create test gap analysis
|
||||
gap_data = {
|
||||
"user_id": test_context["user_id"],
|
||||
"website_url": "https://example.com",
|
||||
"competitor_urls": ["https://competitor1.com", "https://competitor2.com"],
|
||||
"target_keywords": [
|
||||
{"keyword": "AI ethics in business", "search_volume": 5000, "competition": "low"},
|
||||
{"keyword": "digital transformation ROI", "search_volume": 8000, "competition": "medium"}
|
||||
],
|
||||
"analysis_results": {
|
||||
"content_gaps": [
|
||||
{"topic": "AI Ethics", "priority": "high", "impact_score": 0.9},
|
||||
{"topic": "Digital Transformation ROI", "priority": "medium", "impact_score": 0.7}
|
||||
],
|
||||
"keyword_opportunities": [
|
||||
{"keyword": "AI ethics in business", "search_volume": 5000, "competition": "low"},
|
||||
{"keyword": "digital transformation ROI", "search_volume": 8000, "competition": "medium"}
|
||||
],
|
||||
"competitor_insights": [
|
||||
{"competitor": "Competitor A", "strength": "Technical content", "weakness": "Practical guides"},
|
||||
{"competitor": "Competitor B", "strength": "Case studies", "weakness": "AI focus"}
|
||||
],
|
||||
"opportunities": [
|
||||
{"type": "content", "topic": "AI Ethics", "priority": "high"},
|
||||
{"type": "content", "topic": "ROI Analysis", "priority": "medium"}
|
||||
]
|
||||
},
|
||||
"recommendations": [
|
||||
"Create comprehensive AI ethics guide",
|
||||
"Develop ROI calculator for digital transformation"
|
||||
],
|
||||
"opportunities": [
|
||||
{"type": "content", "topic": "AI Ethics", "priority": "high"},
|
||||
{"type": "content", "topic": "ROI Analysis", "priority": "medium"}
|
||||
]
|
||||
}
|
||||
|
||||
gap_analysis = await db_service.create_content_gap_analysis(gap_data)
|
||||
if gap_analysis:
|
||||
logger.info(f"✅ Created test gap analysis: {gap_analysis.id}")
|
||||
|
||||
logger.info("✅ Test data created successfully")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Error creating test data: {str(e)}")
|
||||
raise
|
||||
|
||||
async def cleanup_test_data(db_session, test_context: Dict[str, Any]):
|
||||
"""Clean up test data from the database."""
|
||||
try:
|
||||
from services.content_planning_db import ContentPlanningDBService
|
||||
|
||||
db_service = ContentPlanningDBService(db_session)
|
||||
|
||||
# Clean up gap analysis (get by user_id and delete)
|
||||
gap_analyses = await db_service.get_user_content_gap_analyses(test_context["user_id"])
|
||||
for gap_analysis in gap_analyses:
|
||||
await db_service.delete_content_gap_analysis(gap_analysis.id)
|
||||
|
||||
# Clean up strategy
|
||||
await db_service.delete_content_strategy(test_context["strategy_id"])
|
||||
|
||||
logger.info("✅ Test data cleaned up successfully")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Error cleaning up test data: {str(e)}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Configure logging
|
||||
logger.remove()
|
||||
logger.add(sys.stderr, level="INFO", format="<green>{time:HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>")
|
||||
|
||||
# Run the test
|
||||
success = asyncio.run(test_real_database_integration())
|
||||
|
||||
if success:
|
||||
logger.info("✅ Real database integration test completed successfully!")
|
||||
sys.exit(0)
|
||||
else:
|
||||
logger.error("❌ Real database integration test failed!")
|
||||
sys.exit(1)
|
||||
179
backend/test/test_seo_tools.py
Normal file
179
backend/test/test_seo_tools.py
Normal file
@@ -0,0 +1,179 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test Script for AI SEO Tools API
|
||||
|
||||
This script tests all the migrated SEO tools endpoints to ensure
|
||||
they are working correctly after migration to FastAPI.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import aiohttp
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
BASE_URL = "http://localhost:8000"
|
||||
|
||||
async def test_endpoint(session, endpoint, method="GET", data=None):
|
||||
"""Test a single endpoint"""
|
||||
url = f"{BASE_URL}{endpoint}"
|
||||
|
||||
try:
|
||||
if method == "POST":
|
||||
async with session.post(url, json=data) as response:
|
||||
result = await response.json()
|
||||
return {
|
||||
"endpoint": endpoint,
|
||||
"status": response.status,
|
||||
"success": response.status == 200,
|
||||
"response": result
|
||||
}
|
||||
else:
|
||||
async with session.get(url) as response:
|
||||
result = await response.json()
|
||||
return {
|
||||
"endpoint": endpoint,
|
||||
"status": response.status,
|
||||
"success": response.status == 200,
|
||||
"response": result
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
"endpoint": endpoint,
|
||||
"status": 0,
|
||||
"success": False,
|
||||
"error": str(e)
|
||||
}
|
||||
|
||||
async def run_seo_tools_tests():
|
||||
"""Run comprehensive tests for all SEO tools"""
|
||||
|
||||
print("🚀 Starting AI SEO Tools API Tests")
|
||||
print("=" * 50)
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
|
||||
# Test health endpoint
|
||||
print("\n1. Testing Health Endpoints...")
|
||||
health_tests = [
|
||||
("/api/seo/health", "GET", None),
|
||||
("/api/seo/tools/status", "GET", None)
|
||||
]
|
||||
|
||||
for endpoint, method, data in health_tests:
|
||||
result = await test_endpoint(session, endpoint, method, data)
|
||||
status = "✅ PASS" if result["success"] else "❌ FAIL"
|
||||
print(f" {status} {endpoint} - Status: {result['status']}")
|
||||
|
||||
# Test meta description generation
|
||||
print("\n2. Testing Meta Description Generation...")
|
||||
meta_desc_data = {
|
||||
"keywords": ["SEO", "content marketing", "digital strategy"],
|
||||
"tone": "Professional",
|
||||
"search_intent": "Informational Intent",
|
||||
"language": "English"
|
||||
}
|
||||
|
||||
result = await test_endpoint(session, "/api/seo/meta-description", "POST", meta_desc_data)
|
||||
status = "✅ PASS" if result["success"] else "❌ FAIL"
|
||||
print(f" {status} Meta Description Generation - Status: {result['status']}")
|
||||
|
||||
if result["success"]:
|
||||
data = result["response"].get("data", {})
|
||||
descriptions = data.get("meta_descriptions", [])
|
||||
print(f" Generated {len(descriptions)} meta descriptions")
|
||||
|
||||
# Test PageSpeed analysis
|
||||
print("\n3. Testing PageSpeed Analysis...")
|
||||
pagespeed_data = {
|
||||
"url": "https://example.com",
|
||||
"strategy": "DESKTOP",
|
||||
"categories": ["performance"]
|
||||
}
|
||||
|
||||
result = await test_endpoint(session, "/api/seo/pagespeed-analysis", "POST", pagespeed_data)
|
||||
status = "✅ PASS" if result["success"] else "❌ FAIL"
|
||||
print(f" {status} PageSpeed Analysis - Status: {result['status']}")
|
||||
|
||||
# Test sitemap analysis
|
||||
print("\n4. Testing Sitemap Analysis...")
|
||||
sitemap_data = {
|
||||
"sitemap_url": "https://www.google.com/sitemap.xml",
|
||||
"analyze_content_trends": False,
|
||||
"analyze_publishing_patterns": False
|
||||
}
|
||||
|
||||
result = await test_endpoint(session, "/api/seo/sitemap-analysis", "POST", sitemap_data)
|
||||
status = "✅ PASS" if result["success"] else "❌ FAIL"
|
||||
print(f" {status} Sitemap Analysis - Status: {result['status']}")
|
||||
|
||||
# Test OpenGraph generation
|
||||
print("\n5. Testing OpenGraph Generation...")
|
||||
og_data = {
|
||||
"url": "https://example.com",
|
||||
"title_hint": "Test Page",
|
||||
"description_hint": "Test description",
|
||||
"platform": "General"
|
||||
}
|
||||
|
||||
result = await test_endpoint(session, "/api/seo/opengraph-tags", "POST", og_data)
|
||||
status = "✅ PASS" if result["success"] else "❌ FAIL"
|
||||
print(f" {status} OpenGraph Generation - Status: {result['status']}")
|
||||
|
||||
# Test on-page SEO analysis
|
||||
print("\n6. Testing On-Page SEO Analysis...")
|
||||
onpage_data = {
|
||||
"url": "https://example.com",
|
||||
"target_keywords": ["test", "example"],
|
||||
"analyze_images": True,
|
||||
"analyze_content_quality": True
|
||||
}
|
||||
|
||||
result = await test_endpoint(session, "/api/seo/on-page-analysis", "POST", onpage_data)
|
||||
status = "✅ PASS" if result["success"] else "❌ FAIL"
|
||||
print(f" {status} On-Page SEO Analysis - Status: {result['status']}")
|
||||
|
||||
# Test technical SEO analysis
|
||||
print("\n7. Testing Technical SEO Analysis...")
|
||||
technical_data = {
|
||||
"url": "https://example.com",
|
||||
"crawl_depth": 2,
|
||||
"include_external_links": True,
|
||||
"analyze_performance": True
|
||||
}
|
||||
|
||||
result = await test_endpoint(session, "/api/seo/technical-seo", "POST", technical_data)
|
||||
status = "✅ PASS" if result["success"] else "❌ FAIL"
|
||||
print(f" {status} Technical SEO Analysis - Status: {result['status']}")
|
||||
|
||||
# Test workflow endpoints
|
||||
print("\n8. Testing Workflow Endpoints...")
|
||||
|
||||
# Website audit workflow
|
||||
audit_data = {
|
||||
"website_url": "https://example.com",
|
||||
"workflow_type": "complete_audit",
|
||||
"target_keywords": ["test", "example"]
|
||||
}
|
||||
|
||||
result = await test_endpoint(session, "/api/seo/workflow/website-audit", "POST", audit_data)
|
||||
status = "✅ PASS" if result["success"] else "❌ FAIL"
|
||||
print(f" {status} Website Audit Workflow - Status: {result['status']}")
|
||||
|
||||
# Content analysis workflow
|
||||
content_data = {
|
||||
"website_url": "https://example.com",
|
||||
"workflow_type": "content_analysis",
|
||||
"target_keywords": ["content", "strategy"]
|
||||
}
|
||||
|
||||
result = await test_endpoint(session, "/api/seo/workflow/content-analysis", "POST", content_data)
|
||||
status = "✅ PASS" if result["success"] else "❌ FAIL"
|
||||
print(f" {status} Content Analysis Workflow - Status: {result['status']}")
|
||||
|
||||
print("\n" + "=" * 50)
|
||||
print("🎉 SEO Tools API Testing Completed!")
|
||||
print("\nNote: Some tests may show connection errors if the server is not running.")
|
||||
print("Start the server with: uvicorn app:app --reload --host 0.0.0.0 --port 8000")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(run_seo_tools_tests())
|
||||
83
backend/test/test_session_management.py
Normal file
83
backend/test/test_session_management.py
Normal file
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test script to verify session management and duplicate prevention.
|
||||
This script tests the session cleanup and duplicate prevention features.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
# Add the current directory to the Python path
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
def test_session_management():
|
||||
"""Test session management features."""
|
||||
try:
|
||||
from api.content_planning.services.calendar_generation_service import CalendarGenerationService
|
||||
|
||||
print("🧪 Testing Session Management")
|
||||
print("=" * 50)
|
||||
|
||||
# Initialize service
|
||||
service = CalendarGenerationService(None) # No DB needed for this test
|
||||
|
||||
# Test 1: Initialize first session
|
||||
print("\n📋 Test 1: Initialize first session")
|
||||
request_data_1 = {
|
||||
"user_id": 1,
|
||||
"strategy_id": 1,
|
||||
"calendar_type": "monthly",
|
||||
"industry": "technology",
|
||||
"business_size": "sme"
|
||||
}
|
||||
|
||||
session_id_1 = f"test-session-{int(datetime.now().timestamp())}-1000"
|
||||
success_1 = service.initialize_orchestrator_session(session_id_1, request_data_1)
|
||||
print(f"✅ First session initialized: {success_1}")
|
||||
print(f"📊 Available sessions: {list(service.orchestrator_sessions.keys())}")
|
||||
|
||||
# Test 2: Try to initialize second session for same user (should fail)
|
||||
print("\n📋 Test 2: Try to initialize second session for same user")
|
||||
session_id_2 = f"test-session-{int(datetime.now().timestamp())}-2000"
|
||||
success_2 = service.initialize_orchestrator_session(session_id_2, request_data_1)
|
||||
print(f"❌ Second session should fail: {success_2}")
|
||||
print(f"📊 Available sessions: {list(service.orchestrator_sessions.keys())}")
|
||||
|
||||
# Test 3: Check active session for user
|
||||
print("\n📋 Test 3: Check active session for user")
|
||||
active_session = service._get_active_session_for_user(1)
|
||||
print(f"✅ Active session for user 1: {active_session}")
|
||||
|
||||
# Test 4: Initialize session for different user (should succeed)
|
||||
print("\n📋 Test 4: Initialize session for different user")
|
||||
request_data_2 = {
|
||||
"user_id": 2,
|
||||
"strategy_id": 2,
|
||||
"calendar_type": "weekly",
|
||||
"industry": "finance",
|
||||
"business_size": "enterprise"
|
||||
}
|
||||
|
||||
session_id_3 = f"test-session-{int(datetime.now().timestamp())}-3000"
|
||||
success_3 = service.initialize_orchestrator_session(session_id_3, request_data_2)
|
||||
print(f"✅ Third session for different user: {success_3}")
|
||||
print(f"📊 Available sessions: {list(service.orchestrator_sessions.keys())}")
|
||||
|
||||
# Test 5: Test session cleanup
|
||||
print("\n📋 Test 5: Test session cleanup")
|
||||
print(f"📊 Sessions before cleanup: {len(service.orchestrator_sessions)}")
|
||||
service._cleanup_old_sessions(1)
|
||||
print(f"📊 Sessions after cleanup: {len(service.orchestrator_sessions)}")
|
||||
|
||||
print("\n🎉 Session management tests completed successfully!")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Test failed: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_session_management()
|
||||
73
backend/test/test_simple_grounding.py
Normal file
73
backend/test/test_simple_grounding.py
Normal file
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Simple test script to verify basic grounding functionality.
|
||||
|
||||
This script tests the core components without triggering API overload.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# Add the backend directory to the Python path
|
||||
backend_dir = Path(__file__).parent
|
||||
sys.path.insert(0, str(backend_dir))
|
||||
|
||||
from loguru import logger
|
||||
from services.llm_providers.gemini_grounded_provider import GeminiGroundedProvider
|
||||
|
||||
async def test_basic_functionality():
|
||||
"""Test basic grounding functionality."""
|
||||
try:
|
||||
logger.info("🧪 Testing Basic Grounding Functionality")
|
||||
|
||||
# Initialize provider
|
||||
provider = GeminiGroundedProvider()
|
||||
logger.info("✅ Provider initialized successfully")
|
||||
|
||||
# Test prompt building
|
||||
prompt = "Write a short LinkedIn post about AI trends"
|
||||
grounded_prompt = provider._build_grounded_prompt(prompt, "linkedin_post")
|
||||
logger.info(f"✅ Grounded prompt built: {len(grounded_prompt)} characters")
|
||||
|
||||
# Test content processing
|
||||
test_content = "AI is transforming industries #AI #Technology"
|
||||
processed = provider._process_post_content(test_content)
|
||||
logger.info(f"✅ Content processed: {len(processed.get('hashtags', []))} hashtags found")
|
||||
|
||||
logger.info("🎉 Basic functionality test completed successfully!")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Basic functionality test failed: {str(e)}")
|
||||
return False
|
||||
|
||||
async def main():
|
||||
"""Main test function."""
|
||||
logger.info("🚀 Starting Simple Grounding Test")
|
||||
logger.info("=" * 50)
|
||||
|
||||
success = await test_basic_functionality()
|
||||
|
||||
if success:
|
||||
logger.info("\n🎉 SUCCESS: Basic grounding functionality is working!")
|
||||
logger.info("✅ Provider initialization successful")
|
||||
logger.info("✅ Prompt building working")
|
||||
logger.info("✅ Content processing working")
|
||||
logger.info("✅ Ready for API integration")
|
||||
else:
|
||||
logger.error("\n❌ FAILURE: Basic functionality test failed")
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Configure logging
|
||||
logger.remove()
|
||||
logger.add(
|
||||
sys.stderr,
|
||||
format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>",
|
||||
level="INFO"
|
||||
)
|
||||
|
||||
# Run the test
|
||||
asyncio.run(main())
|
||||
40
backend/test/test_simple_schema.py
Normal file
40
backend/test/test_simple_schema.py
Normal file
@@ -0,0 +1,40 @@
|
||||
import asyncio
|
||||
from services.llm_providers.gemini_provider import gemini_structured_json_response
|
||||
|
||||
async def test_simple_schema():
|
||||
"""Test with a very simple schema to see if structured output works at all"""
|
||||
|
||||
# Very simple schema
|
||||
simple_schema = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"type": "string"},
|
||||
"age": {"type": "integer"}
|
||||
}
|
||||
}
|
||||
|
||||
simple_prompt = "Generate a person with a name and age."
|
||||
|
||||
print("Testing simple schema...")
|
||||
print(f"Schema: {simple_schema}")
|
||||
print(f"Prompt: {simple_prompt}")
|
||||
print("\n" + "="*50 + "\n")
|
||||
|
||||
try:
|
||||
result = gemini_structured_json_response(
|
||||
prompt=simple_prompt,
|
||||
schema=simple_schema,
|
||||
temperature=0.3,
|
||||
max_tokens=100
|
||||
)
|
||||
|
||||
print("Result:")
|
||||
print(result)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(test_simple_schema())
|
||||
126
backend/test/test_step1_only.py
Normal file
126
backend/test/test_step1_only.py
Normal file
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Simple Test Script for Step 1 Only
|
||||
|
||||
This script tests only Step 1 to verify imports are working correctly.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
from typing import Dict, Any
|
||||
from loguru import logger
|
||||
|
||||
# Add the backend directory to the path
|
||||
backend_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
if backend_dir not in sys.path:
|
||||
sys.path.insert(0, backend_dir)
|
||||
|
||||
# Add the services directory to the path
|
||||
services_dir = os.path.join(backend_dir, "services")
|
||||
if services_dir not in sys.path:
|
||||
sys.path.insert(0, services_dir)
|
||||
|
||||
async def test_step1_only():
|
||||
"""Test only Step 1 to verify imports work."""
|
||||
|
||||
try:
|
||||
logger.info("🚀 Starting test of Step 1 only")
|
||||
|
||||
# Test data
|
||||
test_context = {
|
||||
"user_id": 1,
|
||||
"strategy_id": 1,
|
||||
"calendar_duration": 7,
|
||||
"posting_preferences": {
|
||||
"posting_frequency": "daily",
|
||||
"preferred_days": ["monday", "wednesday", "friday"],
|
||||
"preferred_times": ["09:00", "12:00", "15:00"],
|
||||
"content_per_day": 2
|
||||
}
|
||||
}
|
||||
|
||||
# Test Step 1: Content Strategy Analysis
|
||||
logger.info("📋 Testing Step 1: Content Strategy Analysis")
|
||||
try:
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.steps.phase1.phase1_steps import ContentStrategyAnalysisStep
|
||||
from services.calendar_generation_datasource_framework.data_processing.strategy_data import StrategyDataProcessor
|
||||
|
||||
logger.info("✅ Imports successful")
|
||||
|
||||
# Create strategy processor with mock data for testing
|
||||
strategy_processor = StrategyDataProcessor()
|
||||
|
||||
# Mock strategy data
|
||||
mock_strategy_data = {
|
||||
"strategy_id": 1,
|
||||
"strategy_name": "Test Strategy",
|
||||
"industry": "technology",
|
||||
"target_audience": {
|
||||
"primary": "Tech professionals",
|
||||
"secondary": "Business leaders",
|
||||
"demographics": {"age_range": "25-45", "location": "Global"}
|
||||
},
|
||||
"content_pillars": [
|
||||
"AI and Machine Learning",
|
||||
"Digital Transformation",
|
||||
"Innovation and Technology Trends",
|
||||
"Business Strategy and Growth"
|
||||
],
|
||||
"business_objectives": [
|
||||
"Increase brand awareness by 40%",
|
||||
"Generate 500 qualified leads per month",
|
||||
"Establish thought leadership"
|
||||
],
|
||||
"target_metrics": {"awareness": "website_traffic", "leads": "lead_generation"},
|
||||
"quality_indicators": {"data_completeness": 0.8, "strategic_alignment": 0.9}
|
||||
}
|
||||
|
||||
# Mock the get_strategy_data method for testing
|
||||
async def mock_get_strategy_data(strategy_id):
|
||||
return mock_strategy_data
|
||||
|
||||
strategy_processor.get_strategy_data = mock_get_strategy_data
|
||||
|
||||
# Mock the validate_data method
|
||||
async def mock_validate_data(data):
|
||||
return {
|
||||
"quality_score": 0.85,
|
||||
"missing_fields": [],
|
||||
"recommendations": []
|
||||
}
|
||||
|
||||
strategy_processor.validate_data = mock_validate_data
|
||||
|
||||
step1 = ContentStrategyAnalysisStep()
|
||||
step1.strategy_processor = strategy_processor
|
||||
|
||||
result1 = await step1.execute(test_context)
|
||||
logger.info(f"✅ Step 1 completed: {result1.get('status')}")
|
||||
logger.info(f" Quality Score: {result1.get('quality_score')}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Step 1 failed: {str(e)}")
|
||||
return False
|
||||
|
||||
logger.info("🎉 Step 1 test completed successfully!")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Test failed with error: {str(e)}")
|
||||
return False
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Configure logging
|
||||
logger.remove()
|
||||
logger.add(sys.stderr, level="INFO", format="<green>{time:HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>")
|
||||
|
||||
# Run the test
|
||||
success = asyncio.run(test_step1_only())
|
||||
|
||||
if success:
|
||||
logger.info("✅ Test completed successfully!")
|
||||
sys.exit(0)
|
||||
else:
|
||||
logger.error("❌ Test failed!")
|
||||
sys.exit(1)
|
||||
85
backend/test/test_step2.py
Normal file
85
backend/test/test_step2.py
Normal file
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test script for Step 2 specifically
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Add the backend directory to the path
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.steps.phase2.step2_implementation import Step2Implementation
|
||||
|
||||
async def test_step2():
|
||||
"""Test Step 2 implementation."""
|
||||
|
||||
print("🧪 Testing Step 2: Gap Analysis & Opportunity Identification")
|
||||
|
||||
# Create test context
|
||||
context = {
|
||||
"user_id": 1,
|
||||
"strategy_id": 1,
|
||||
"calendar_type": "monthly",
|
||||
"industry": "technology",
|
||||
"business_size": "sme",
|
||||
"user_data": {
|
||||
"onboarding_data": {
|
||||
"posting_preferences": {
|
||||
"daily": 2,
|
||||
"weekly": 10,
|
||||
"monthly": 40
|
||||
},
|
||||
"posting_days": [
|
||||
"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"
|
||||
],
|
||||
"optimal_times": [
|
||||
"09:00", "12:00", "15:00", "18:00", "20:00"
|
||||
]
|
||||
},
|
||||
"strategy_data": {
|
||||
"industry": "technology",
|
||||
"target_audience": {
|
||||
"primary": "Tech professionals",
|
||||
"secondary": "Business leaders"
|
||||
},
|
||||
"business_objectives": [
|
||||
"Increase brand awareness",
|
||||
"Generate leads",
|
||||
"Establish thought leadership"
|
||||
]
|
||||
}
|
||||
},
|
||||
"step_results": {},
|
||||
"quality_scores": {}
|
||||
}
|
||||
|
||||
try:
|
||||
# Create Step 2 instance
|
||||
step2 = Step2Implementation()
|
||||
|
||||
print("✅ Step 2 instance created successfully")
|
||||
|
||||
# Test Step 2 execution
|
||||
print("🔄 Executing Step 2...")
|
||||
result = await step2.run(context)
|
||||
|
||||
if result:
|
||||
print("✅ Step 2 executed successfully!")
|
||||
print(f"Status: {result.get('status')}")
|
||||
print(f"Quality Score: {result.get('quality_score')}")
|
||||
print(f"Execution Time: {result.get('execution_time')}")
|
||||
|
||||
if result.get('status') == 'error':
|
||||
print(f"❌ Step 2 Error: {result.get('error_message')}")
|
||||
else:
|
||||
print("❌ Step 2 returned None")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error testing Step 2: {e}")
|
||||
import traceback
|
||||
print(f"📋 Traceback: {traceback.format_exc()}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(test_step2())
|
||||
50
backend/test/test_step4_data.py
Normal file
50
backend/test/test_step4_data.py
Normal file
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test script for Step 4 data
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Add the backend directory to the path
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
async def test_step4_data():
|
||||
"""Test Step 4 data processing."""
|
||||
|
||||
print("🧪 Testing Step 4: Calendar Framework & Timeline Data")
|
||||
|
||||
try:
|
||||
# Test comprehensive user data
|
||||
from services.calendar_generation_datasource_framework.data_processing.comprehensive_user_data import ComprehensiveUserDataProcessor
|
||||
|
||||
processor = ComprehensiveUserDataProcessor()
|
||||
data = await processor.get_comprehensive_user_data(1, 1)
|
||||
|
||||
print("✅ Comprehensive user data retrieved successfully")
|
||||
print(f"📊 Data keys: {list(data.keys())}")
|
||||
|
||||
onboarding_data = data.get('onboarding_data', {})
|
||||
print(f"📋 Onboarding data keys: {list(onboarding_data.keys())}")
|
||||
|
||||
posting_preferences = onboarding_data.get('posting_preferences')
|
||||
posting_days = onboarding_data.get('posting_days')
|
||||
optimal_times = onboarding_data.get('optimal_times')
|
||||
|
||||
print(f"📅 Posting preferences: {posting_preferences}")
|
||||
print(f"📅 Posting days: {posting_days}")
|
||||
print(f"⏰ Optimal times: {optimal_times}")
|
||||
|
||||
if posting_preferences and posting_days:
|
||||
print("✅ Step 4 data requirements met!")
|
||||
else:
|
||||
print("❌ Step 4 data requirements NOT met!")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error testing Step 4 data: {e}")
|
||||
import traceback
|
||||
print(f"📋 Traceback: {traceback.format_exc()}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(test_step4_data())
|
||||
168
backend/test/test_step4_data_debug.py
Normal file
168
backend/test/test_step4_data_debug.py
Normal file
@@ -0,0 +1,168 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Debug Step 4 data issues - check what data is available from database.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import time
|
||||
from loguru import logger
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Add the backend directory to the path
|
||||
backend_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
if backend_dir not in sys.path:
|
||||
sys.path.insert(0, backend_dir)
|
||||
|
||||
async def test_step4_data_sources():
|
||||
"""Test what data Step 4 is actually receiving."""
|
||||
try:
|
||||
logger.info("🧪 Testing Step 4 data sources")
|
||||
|
||||
# Test 1: Onboarding Data Service
|
||||
logger.info("📋 Test 1: Onboarding Data Service")
|
||||
try:
|
||||
from services.onboarding_data_service import OnboardingDataService
|
||||
onboarding_service = OnboardingDataService()
|
||||
|
||||
# Test with user_id = 1
|
||||
onboarding_data = onboarding_service.get_personalized_ai_inputs(1)
|
||||
|
||||
logger.info(f"📊 Onboarding data keys: {list(onboarding_data.keys()) if onboarding_data else 'None'}")
|
||||
|
||||
if onboarding_data:
|
||||
# Check for posting preferences
|
||||
posting_prefs = onboarding_data.get("posting_preferences")
|
||||
posting_days = onboarding_data.get("posting_days")
|
||||
optimal_times = onboarding_data.get("optimal_times")
|
||||
|
||||
logger.info(f"📅 Posting preferences: {posting_prefs}")
|
||||
logger.info(f"📅 Posting days: {posting_days}")
|
||||
logger.info(f"📅 Optimal times: {optimal_times}")
|
||||
|
||||
# Check website analysis
|
||||
website_analysis = onboarding_data.get("website_analysis", {})
|
||||
logger.info(f"🌐 Website analysis keys: {list(website_analysis.keys())}")
|
||||
|
||||
# Check competitor analysis
|
||||
competitor_analysis = onboarding_data.get("competitor_analysis", {})
|
||||
logger.info(f"🏢 Competitor analysis keys: {list(competitor_analysis.keys())}")
|
||||
|
||||
# Check keyword analysis
|
||||
keyword_analysis = onboarding_data.get("keyword_analysis", {})
|
||||
logger.info(f"🔍 Keyword analysis keys: {list(keyword_analysis.keys())}")
|
||||
|
||||
else:
|
||||
logger.error("❌ No onboarding data returned")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Onboarding service error: {str(e)}")
|
||||
|
||||
# Test 2: Comprehensive User Data Processor
|
||||
logger.info("\n📋 Test 2: Comprehensive User Data Processor")
|
||||
try:
|
||||
from services.calendar_generation_datasource_framework.data_processing.comprehensive_user_data import ComprehensiveUserDataProcessor
|
||||
|
||||
processor = ComprehensiveUserDataProcessor()
|
||||
comprehensive_data = await processor.get_comprehensive_user_data(1, 1)
|
||||
|
||||
logger.info(f"📊 Comprehensive data keys: {list(comprehensive_data.keys()) if comprehensive_data else 'None'}")
|
||||
|
||||
if comprehensive_data:
|
||||
# Check onboarding data
|
||||
onboarding_data = comprehensive_data.get("onboarding_data", {})
|
||||
logger.info(f"👤 Onboarding data keys: {list(onboarding_data.keys())}")
|
||||
|
||||
# Check for posting preferences (Step 4 requirement)
|
||||
posting_prefs = onboarding_data.get("posting_preferences")
|
||||
posting_days = onboarding_data.get("posting_days")
|
||||
optimal_times = onboarding_data.get("optimal_times")
|
||||
|
||||
logger.info(f"📅 Posting preferences: {posting_prefs}")
|
||||
logger.info(f"📅 Posting days: {posting_days}")
|
||||
logger.info(f"📅 Optimal times: {optimal_times}")
|
||||
|
||||
# Check strategy data
|
||||
strategy_data = comprehensive_data.get("strategy_data", {})
|
||||
logger.info(f"🎯 Strategy data keys: {list(strategy_data.keys())}")
|
||||
|
||||
# Check gap analysis
|
||||
gap_analysis = comprehensive_data.get("gap_analysis", {})
|
||||
logger.info(f"📊 Gap analysis keys: {list(gap_analysis.keys())}")
|
||||
|
||||
else:
|
||||
logger.error("❌ No comprehensive data returned")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Comprehensive data processor error: {str(e)}")
|
||||
|
||||
# Test 3: Database Connection
|
||||
logger.info("\n📋 Test 3: Database Connection")
|
||||
try:
|
||||
from services.database import get_db_session
|
||||
from models.onboarding import OnboardingSession, WebsiteAnalysis
|
||||
|
||||
session = get_db_session()
|
||||
|
||||
# Check for onboarding sessions
|
||||
onboarding_sessions = session.query(OnboardingSession).all()
|
||||
logger.info(f"📊 Found {len(onboarding_sessions)} onboarding sessions")
|
||||
|
||||
if onboarding_sessions:
|
||||
for i, session_data in enumerate(onboarding_sessions):
|
||||
logger.info(f" Session {i+1}: user_id={session_data.user_id}, created={session_data.created_at}")
|
||||
|
||||
# Check for website analysis
|
||||
website_analyses = session.query(WebsiteAnalysis).filter(
|
||||
WebsiteAnalysis.session_id == session_data.id
|
||||
).all()
|
||||
logger.info(f" Website analyses: {len(website_analyses)}")
|
||||
|
||||
else:
|
||||
logger.warning("⚠️ No onboarding sessions found in database")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Database connection error: {str(e)}")
|
||||
|
||||
# Test 4: Step 4 Direct Test
|
||||
logger.info("\n📋 Test 4: Step 4 Direct Test")
|
||||
try:
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.steps.phase2.step4_implementation import CalendarFrameworkStep
|
||||
|
||||
step4 = CalendarFrameworkStep()
|
||||
|
||||
# Create mock context
|
||||
context = {
|
||||
"user_id": 1,
|
||||
"strategy_id": 1,
|
||||
"calendar_type": "monthly",
|
||||
"industry": "technology",
|
||||
"business_size": "sme"
|
||||
}
|
||||
|
||||
# Try to execute Step 4
|
||||
logger.info("🔄 Executing Step 4...")
|
||||
result = await step4.execute(context)
|
||||
|
||||
logger.info(f"✅ Step 4 executed successfully")
|
||||
logger.info(f"📊 Result keys: {list(result.keys()) if result else 'None'}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Step 4 execution error: {str(e)}")
|
||||
import traceback
|
||||
logger.error(f"📋 Traceback: {traceback.format_exc()}")
|
||||
|
||||
logger.info("\n🎯 Step 4 Data Debug Complete")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Error in data debug test: {str(e)}")
|
||||
import traceback
|
||||
logger.error(f"📋 Traceback: {traceback.format_exc()}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Configure logging
|
||||
logger.remove()
|
||||
logger.add(sys.stderr, level="INFO", format="<green>{time:HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>")
|
||||
|
||||
# Run the test
|
||||
asyncio.run(test_step4_data_sources())
|
||||
63
backend/test/test_step4_execution.py
Normal file
63
backend/test/test_step4_execution.py
Normal file
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test script for Step 4 execution
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Add the backend directory to the path
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
async def test_step4_execution():
|
||||
"""Test Step 4 execution directly."""
|
||||
|
||||
print("🧪 Testing Step 4: Calendar Framework & Timeline Execution")
|
||||
|
||||
try:
|
||||
# Import Step 4
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.steps.phase2.step4_implementation import CalendarFrameworkStep
|
||||
|
||||
# Create test context
|
||||
context = {
|
||||
"user_id": 1,
|
||||
"strategy_id": 1,
|
||||
"calendar_type": "monthly",
|
||||
"industry": "technology",
|
||||
"business_size": "sme",
|
||||
"step_results": {},
|
||||
"quality_scores": {}
|
||||
}
|
||||
|
||||
# Create Step 4 instance
|
||||
step4 = CalendarFrameworkStep()
|
||||
print("✅ Step 4 instance created successfully")
|
||||
|
||||
# Test Step 4 execution
|
||||
print("🔄 Executing Step 4...")
|
||||
result = await step4.run(context)
|
||||
|
||||
if result:
|
||||
print("✅ Step 4 executed successfully!")
|
||||
print(f"Status: {result.get('status')}")
|
||||
print(f"Quality Score: {result.get('quality_score')}")
|
||||
print(f"Execution Time: {result.get('execution_time')}")
|
||||
|
||||
if result.get('status') == 'error':
|
||||
print(f"❌ Step 4 Error: {result.get('error_message')}")
|
||||
else:
|
||||
print("📊 Step 4 Results:")
|
||||
print(f" - Calendar Structure: {result.get('calendar_structure', {}).get('type')}")
|
||||
print(f" - Timeline Config: {result.get('timeline_config', {}).get('total_weeks')} weeks")
|
||||
print(f" - Duration Control: {result.get('duration_control', {}).get('validation_passed')}")
|
||||
else:
|
||||
print("❌ Step 4 returned None")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error testing Step 4 execution: {e}")
|
||||
import traceback
|
||||
print(f"📋 Traceback: {traceback.format_exc()}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(test_step4_execution())
|
||||
245
backend/test/test_step4_implementation.py
Normal file
245
backend/test/test_step4_implementation.py
Normal file
@@ -0,0 +1,245 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test Script for Step 4 Implementation
|
||||
|
||||
This script tests the Step 4 (Calendar Framework and Timeline) implementation
|
||||
to ensure it works correctly with real AI services and data processing.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# Add the backend directory to the Python path
|
||||
backend_dir = Path(__file__).parent
|
||||
sys.path.insert(0, str(backend_dir))
|
||||
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.steps.phase2.phase2_steps import CalendarFrameworkStep
|
||||
from services.calendar_generation_datasource_framework.data_processing import ComprehensiveUserDataProcessor
|
||||
|
||||
|
||||
async def test_step4_implementation():
|
||||
"""Test Step 4 implementation with real data processing."""
|
||||
print("🧪 Testing Step 4: Calendar Framework and Timeline Implementation")
|
||||
|
||||
try:
|
||||
# Initialize Step 4
|
||||
step4 = CalendarFrameworkStep()
|
||||
print("✅ Step 4 initialized successfully")
|
||||
|
||||
# Initialize data processor
|
||||
data_processor = ComprehensiveUserDataProcessor()
|
||||
print("✅ Data processor initialized successfully")
|
||||
|
||||
# Test context data
|
||||
context = {
|
||||
"user_id": 1,
|
||||
"strategy_id": 1,
|
||||
"calendar_type": "monthly",
|
||||
"industry": "technology",
|
||||
"business_size": "sme"
|
||||
}
|
||||
|
||||
print(f"📊 Testing with context: {context}")
|
||||
|
||||
# Execute Step 4
|
||||
print("🔄 Executing Step 4...")
|
||||
result = await step4.execute(context)
|
||||
|
||||
# Validate results
|
||||
print("📋 Step 4 Results:")
|
||||
print(f" - Step Number: {result.get('stepNumber')}")
|
||||
print(f" - Step Name: {result.get('stepName')}")
|
||||
print(f" - Quality Score: {result.get('qualityScore', 0):.2f}")
|
||||
print(f" - Execution Time: {result.get('executionTime')}")
|
||||
print(f" - Data Sources Used: {result.get('dataSourcesUsed')}")
|
||||
|
||||
# Validate calendar structure
|
||||
calendar_structure = result.get('results', {}).get('calendarStructure', {})
|
||||
print(f" - Calendar Type: {calendar_structure.get('type')}")
|
||||
print(f" - Total Weeks: {calendar_structure.get('totalWeeks')}")
|
||||
print(f" - Content Distribution: {calendar_structure.get('contentDistribution')}")
|
||||
|
||||
# Validate timeline configuration
|
||||
timeline_config = result.get('results', {}).get('timelineConfiguration', {})
|
||||
print(f" - Start Date: {timeline_config.get('startDate')}")
|
||||
print(f" - End Date: {timeline_config.get('endDate')}")
|
||||
print(f" - Total Days: {timeline_config.get('totalDays')}")
|
||||
print(f" - Posting Days: {timeline_config.get('postingDays')}")
|
||||
|
||||
# Validate quality gates
|
||||
duration_control = result.get('results', {}).get('durationControl', {})
|
||||
strategic_alignment = result.get('results', {}).get('strategicAlignment', {})
|
||||
|
||||
print(f" - Duration Accuracy: {duration_control.get('accuracyScore', 0):.1%}")
|
||||
print(f" - Strategic Alignment: {strategic_alignment.get('alignmentScore', 0):.1%}")
|
||||
|
||||
# Validate insights and recommendations
|
||||
insights = result.get('insights', [])
|
||||
recommendations = result.get('recommendations', [])
|
||||
|
||||
print(f" - Insights Count: {len(insights)}")
|
||||
print(f" - Recommendations Count: {len(recommendations)}")
|
||||
|
||||
# Quality validation
|
||||
quality_score = result.get('qualityScore', 0)
|
||||
if quality_score >= 0.85:
|
||||
print(f"✅ Quality Score: {quality_score:.2f} (Excellent)")
|
||||
elif quality_score >= 0.75:
|
||||
print(f"✅ Quality Score: {quality_score:.2f} (Good)")
|
||||
else:
|
||||
print(f"⚠️ Quality Score: {quality_score:.2f} (Needs Improvement)")
|
||||
|
||||
print("✅ Step 4 implementation test completed successfully!")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error testing Step 4: {str(e)}")
|
||||
import traceback
|
||||
print(f"Traceback: {traceback.format_exc()}")
|
||||
return False
|
||||
|
||||
|
||||
async def test_step4_integration():
|
||||
"""Test Step 4 integration with the orchestrator."""
|
||||
print("\n🧪 Testing Step 4 Integration with Orchestrator")
|
||||
|
||||
try:
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.orchestrator import PromptChainOrchestrator
|
||||
|
||||
# Initialize orchestrator
|
||||
orchestrator = PromptChainOrchestrator()
|
||||
print("✅ Orchestrator initialized successfully")
|
||||
|
||||
# Check if Step 4 is properly registered
|
||||
step4 = orchestrator.steps.get("step_04")
|
||||
if step4 and step4.name == "Calendar Framework & Timeline":
|
||||
print("✅ Step 4 properly registered in orchestrator")
|
||||
else:
|
||||
print("❌ Step 4 not properly registered in orchestrator")
|
||||
return False
|
||||
|
||||
# Test context initialization
|
||||
context = await orchestrator._initialize_context(
|
||||
user_id=1,
|
||||
strategy_id=1,
|
||||
calendar_type="monthly",
|
||||
industry="technology",
|
||||
business_size="sme"
|
||||
)
|
||||
print("✅ Context initialization successful")
|
||||
|
||||
# Test Step 4 execution through orchestrator
|
||||
print("🔄 Testing Step 4 execution through orchestrator...")
|
||||
step_result = await step4.execute(context)
|
||||
|
||||
if step_result and step_result.get('stepNumber') == 4:
|
||||
print("✅ Step 4 execution through orchestrator successful")
|
||||
print(f" - Quality Score: {step_result.get('qualityScore', 0):.2f}")
|
||||
else:
|
||||
print("❌ Step 4 execution through orchestrator failed")
|
||||
return False
|
||||
|
||||
print("✅ Step 4 integration test completed successfully!")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error testing Step 4 integration: {str(e)}")
|
||||
import traceback
|
||||
print(f"Traceback: {traceback.format_exc()}")
|
||||
return False
|
||||
|
||||
|
||||
async def test_step4_data_processing():
|
||||
"""Test Step 4 data processing capabilities."""
|
||||
print("\n🧪 Testing Step 4 Data Processing")
|
||||
|
||||
try:
|
||||
from services.calendar_generation_datasource_framework.data_processing import ComprehensiveUserDataProcessor
|
||||
|
||||
# Initialize data processor
|
||||
data_processor = ComprehensiveUserDataProcessor()
|
||||
print("✅ Data processor initialized successfully")
|
||||
|
||||
# Test comprehensive user data retrieval
|
||||
print("🔄 Testing comprehensive user data retrieval...")
|
||||
user_data = await data_processor.get_comprehensive_user_data(1, 1)
|
||||
|
||||
if user_data:
|
||||
print("✅ Comprehensive user data retrieved successfully")
|
||||
print(f" - User ID: {user_data.get('user_id')}")
|
||||
print(f" - Strategy ID: {user_data.get('strategy_id')}")
|
||||
print(f" - Industry: {user_data.get('industry')}")
|
||||
|
||||
# Check for required data sections
|
||||
required_sections = ['onboarding_data', 'strategy_data', 'gap_analysis', 'ai_analysis']
|
||||
for section in required_sections:
|
||||
if section in user_data:
|
||||
print(f" - {section}: Available")
|
||||
else:
|
||||
print(f" - {section}: Missing")
|
||||
else:
|
||||
print("❌ Failed to retrieve comprehensive user data")
|
||||
return False
|
||||
|
||||
print("✅ Step 4 data processing test completed successfully!")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error testing Step 4 data processing: {str(e)}")
|
||||
import traceback
|
||||
print(f"Traceback: {traceback.format_exc()}")
|
||||
return False
|
||||
|
||||
|
||||
async def main():
|
||||
"""Main test function."""
|
||||
print("🚀 Starting Step 4 Implementation Tests")
|
||||
print("=" * 50)
|
||||
|
||||
# Run all tests
|
||||
tests = [
|
||||
test_step4_implementation(),
|
||||
test_step4_integration(),
|
||||
test_step4_data_processing()
|
||||
]
|
||||
|
||||
results = await asyncio.gather(*tests, return_exceptions=True)
|
||||
|
||||
# Summarize results
|
||||
print("\n" + "=" * 50)
|
||||
print("📊 Test Results Summary")
|
||||
print("=" * 50)
|
||||
|
||||
test_names = [
|
||||
"Step 4 Implementation",
|
||||
"Step 4 Integration",
|
||||
"Step 4 Data Processing"
|
||||
]
|
||||
|
||||
passed = 0
|
||||
total = len(results)
|
||||
|
||||
for i, result in enumerate(results):
|
||||
if isinstance(result, Exception):
|
||||
print(f"❌ {test_names[i]}: Failed - {str(result)}")
|
||||
elif result:
|
||||
print(f"✅ {test_names[i]}: Passed")
|
||||
passed += 1
|
||||
else:
|
||||
print(f"❌ {test_names[i]}: Failed")
|
||||
|
||||
print(f"\n🎯 Overall Results: {passed}/{total} tests passed")
|
||||
|
||||
if passed == total:
|
||||
print("🎉 All tests passed! Step 4 implementation is ready for production.")
|
||||
return True
|
||||
else:
|
||||
print("⚠️ Some tests failed. Please review the implementation.")
|
||||
return False
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
success = asyncio.run(main())
|
||||
sys.exit(0 if success else 1)
|
||||
88
backend/test/test_step5_debug.py
Normal file
88
backend/test/test_step5_debug.py
Normal file
@@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test script for Step 5 debugging
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
import time
|
||||
|
||||
# Add the backend directory to the path
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
async def test_step5_debug():
|
||||
"""Debug Step 5 execution specifically."""
|
||||
|
||||
print("🧪 Debugging Step 5: Content Pillar Distribution")
|
||||
|
||||
try:
|
||||
# Import Step 5
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.steps.phase2.step5_implementation import ContentPillarDistributionStep
|
||||
|
||||
# Create test context with data from previous steps
|
||||
context = {
|
||||
"user_id": 1,
|
||||
"strategy_id": 1,
|
||||
"calendar_type": "monthly",
|
||||
"industry": "technology",
|
||||
"business_size": "sme",
|
||||
"previous_step_results": {
|
||||
4: {
|
||||
"results": {
|
||||
"calendarStructure": {
|
||||
"type": "monthly",
|
||||
"total_weeks": 4,
|
||||
"posting_days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
|
||||
"posting_frequency": {
|
||||
"daily": 2,
|
||||
"weekly": 10,
|
||||
"monthly": 40
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"step_results": {},
|
||||
"quality_scores": {}
|
||||
}
|
||||
|
||||
# Create Step 5 instance
|
||||
print("✅ Creating Step 5 instance...")
|
||||
step5 = ContentPillarDistributionStep()
|
||||
print("✅ Step 5 instance created successfully")
|
||||
|
||||
# Test Step 5 execution with timing
|
||||
print("🔄 Executing Step 5...")
|
||||
start_time = time.time()
|
||||
|
||||
result = await step5.run(context)
|
||||
|
||||
execution_time = time.time() - start_time
|
||||
print(f"⏱️ Step 5 execution time: {execution_time:.2f} seconds")
|
||||
|
||||
if result:
|
||||
print("✅ Step 5 executed successfully!")
|
||||
print(f"Status: {result.get('status', 'unknown')}")
|
||||
print(f"Quality Score: {result.get('quality_score', 0)}")
|
||||
print(f"Execution Time: {result.get('execution_time', 'unknown')}")
|
||||
|
||||
if result.get('status') == 'error':
|
||||
print(f"❌ Step 5 Error: {result.get('error_message', 'Unknown error')}")
|
||||
else:
|
||||
print("📊 Step 5 Results:")
|
||||
results = result.get('results', {})
|
||||
print(f" - Pillar Mapping: {results.get('pillarMapping', {}).get('distribution_balance', 0):.1%} balance")
|
||||
print(f" - Theme Development: {results.get('themeDevelopment', {}).get('variety_score', 0):.1%} variety")
|
||||
print(f" - Strategic Validation: {results.get('strategicValidation', {}).get('alignment_score', 0):.1%} alignment")
|
||||
print(f" - Diversity Assurance: {results.get('diversityAssurance', {}).get('diversity_score', 0):.1%} diversity")
|
||||
else:
|
||||
print("❌ Step 5 returned None")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error testing Step 5: {e}")
|
||||
import traceback
|
||||
print(f"📋 Traceback: {traceback.format_exc()}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(test_step5_debug())
|
||||
122
backend/test/test_step5_orchestrator_context.py
Normal file
122
backend/test/test_step5_orchestrator_context.py
Normal file
@@ -0,0 +1,122 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test script for Step 5 with orchestrator context structure
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
import time
|
||||
|
||||
# Add the backend directory to the path
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
async def test_step5_orchestrator_context():
|
||||
"""Test Step 5 with orchestrator context structure."""
|
||||
|
||||
print("🧪 Testing Step 5 with orchestrator context structure")
|
||||
|
||||
try:
|
||||
# Import Step 5
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.steps.phase2.step5_implementation import ContentPillarDistributionStep
|
||||
|
||||
# Create context exactly as the orchestrator does
|
||||
context = {
|
||||
"user_id": 1,
|
||||
"strategy_id": 1,
|
||||
"calendar_type": "monthly",
|
||||
"industry": "technology",
|
||||
"business_size": "sme",
|
||||
"user_data": {
|
||||
"user_id": 1,
|
||||
"strategy_id": 1,
|
||||
"industry": "technology",
|
||||
"onboarding_data": {
|
||||
"posting_preferences": {
|
||||
"daily": 2,
|
||||
"weekly": 10,
|
||||
"monthly": 40
|
||||
},
|
||||
"posting_days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
|
||||
"optimal_times": ["09:00", "12:00", "15:00", "18:00", "20:00"]
|
||||
},
|
||||
"strategy_data": {
|
||||
"content_pillars": [
|
||||
"AI and Machine Learning",
|
||||
"Digital Transformation",
|
||||
"Innovation and Technology Trends",
|
||||
"Business Strategy and Growth"
|
||||
],
|
||||
"business_objectives": [
|
||||
"Increase brand awareness by 40%",
|
||||
"Generate 500 qualified leads per month",
|
||||
"Establish thought leadership in AI/ML space"
|
||||
]
|
||||
}
|
||||
},
|
||||
"step_results": {
|
||||
"step_04": {
|
||||
"stepNumber": 4,
|
||||
"stepName": "Calendar Framework & Timeline",
|
||||
"results": {
|
||||
"calendarStructure": {
|
||||
"type": "monthly",
|
||||
"total_weeks": 4,
|
||||
"posting_days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
|
||||
"posting_frequency": {
|
||||
"daily": 2,
|
||||
"weekly": 10,
|
||||
"monthly": 40
|
||||
},
|
||||
"industry": "technology",
|
||||
"business_size": "sme"
|
||||
}
|
||||
},
|
||||
"qualityScore": 1.0,
|
||||
"executionTime": "2.9s"
|
||||
}
|
||||
},
|
||||
"quality_scores": {},
|
||||
"current_step": 5,
|
||||
"phase": "phase_2_structure"
|
||||
}
|
||||
|
||||
# Create Step 5 instance
|
||||
print("✅ Creating Step 5 instance...")
|
||||
step5 = ContentPillarDistributionStep()
|
||||
print("✅ Step 5 instance created successfully")
|
||||
|
||||
# Test Step 5 execution with timing
|
||||
print("🔄 Executing Step 5...")
|
||||
start_time = time.time()
|
||||
|
||||
result = await step5.run(context)
|
||||
|
||||
execution_time = time.time() - start_time
|
||||
print(f"⏱️ Step 5 execution time: {execution_time:.2f} seconds")
|
||||
|
||||
if result:
|
||||
print("✅ Step 5 executed successfully!")
|
||||
print(f"Status: {result.get('status', 'unknown')}")
|
||||
print(f"Quality Score: {result.get('quality_score', 0)}")
|
||||
print(f"Execution Time: {result.get('execution_time', 'unknown')}")
|
||||
|
||||
if result.get('status') == 'error':
|
||||
print(f"❌ Step 5 Error: {result.get('error_message', 'Unknown error')}")
|
||||
else:
|
||||
print("📊 Step 5 Results:")
|
||||
results = result.get('results', {})
|
||||
print(f" - Pillar Mapping: {results.get('pillarMapping', {}).get('distribution_balance', 0):.1%} balance")
|
||||
print(f" - Theme Development: {results.get('themeDevelopment', {}).get('variety_score', 0):.1%} variety")
|
||||
print(f" - Strategic Validation: {results.get('strategicValidation', {}).get('alignment_score', 0):.1%} alignment")
|
||||
print(f" - Diversity Assurance: {results.get('diversityAssurance', {}).get('diversity_score', 0):.1%} diversity")
|
||||
else:
|
||||
print("❌ Step 5 returned None")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error testing Step 5: {e}")
|
||||
import traceback
|
||||
print(f"📋 Traceback: {traceback.format_exc()}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(test_step5_orchestrator_context())
|
||||
127
backend/test/test_step5_orchestrator_direct.py
Normal file
127
backend/test/test_step5_orchestrator_direct.py
Normal file
@@ -0,0 +1,127 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test script for Step 5 with orchestrator's direct step execution
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
import time
|
||||
|
||||
# Add the backend directory to the path
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
async def test_step5_orchestrator_direct():
|
||||
"""Test Step 5 with orchestrator's direct step execution."""
|
||||
|
||||
print("🧪 Testing Step 5 with orchestrator's direct step execution")
|
||||
|
||||
try:
|
||||
# Import orchestrator and Step 5
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.orchestrator import PromptChainOrchestrator
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.steps.phase2.step5_implementation import ContentPillarDistributionStep
|
||||
|
||||
# Create orchestrator
|
||||
print("✅ Creating orchestrator...")
|
||||
orchestrator = PromptChainOrchestrator()
|
||||
print("✅ Orchestrator created successfully")
|
||||
|
||||
# Get Step 5 from orchestrator
|
||||
step5 = orchestrator.steps["step_05"]
|
||||
print(f"✅ Got Step 5 from orchestrator: {type(step5)}")
|
||||
|
||||
# Create context exactly as the orchestrator does
|
||||
context = {
|
||||
"user_id": 1,
|
||||
"strategy_id": 1,
|
||||
"calendar_type": "monthly",
|
||||
"industry": "technology",
|
||||
"business_size": "sme",
|
||||
"user_data": {
|
||||
"user_id": 1,
|
||||
"strategy_id": 1,
|
||||
"industry": "technology",
|
||||
"onboarding_data": {
|
||||
"posting_preferences": {
|
||||
"daily": 2,
|
||||
"weekly": 10,
|
||||
"monthly": 40
|
||||
},
|
||||
"posting_days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
|
||||
"optimal_times": ["09:00", "12:00", "15:00", "18:00", "20:00"]
|
||||
},
|
||||
"strategy_data": {
|
||||
"content_pillars": [
|
||||
"AI and Machine Learning",
|
||||
"Digital Transformation",
|
||||
"Innovation and Technology Trends",
|
||||
"Business Strategy and Growth"
|
||||
],
|
||||
"business_objectives": [
|
||||
"Increase brand awareness by 40%",
|
||||
"Generate 500 qualified leads per month",
|
||||
"Establish thought leadership in AI/ML space"
|
||||
]
|
||||
}
|
||||
},
|
||||
"step_results": {
|
||||
"step_04": {
|
||||
"stepNumber": 4,
|
||||
"stepName": "Calendar Framework & Timeline",
|
||||
"results": {
|
||||
"calendarStructure": {
|
||||
"type": "monthly",
|
||||
"total_weeks": 4,
|
||||
"posting_days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
|
||||
"posting_frequency": {
|
||||
"daily": 2,
|
||||
"weekly": 10,
|
||||
"monthly": 40
|
||||
},
|
||||
"industry": "technology",
|
||||
"business_size": "sme"
|
||||
}
|
||||
},
|
||||
"qualityScore": 1.0,
|
||||
"executionTime": "2.9s"
|
||||
}
|
||||
},
|
||||
"quality_scores": {},
|
||||
"current_step": 5,
|
||||
"phase": "phase_2_structure"
|
||||
}
|
||||
|
||||
# Test Step 5 execution with timing
|
||||
print("🔄 Executing Step 5 with orchestrator's step...")
|
||||
start_time = time.time()
|
||||
|
||||
result = await step5.run(context)
|
||||
|
||||
execution_time = time.time() - start_time
|
||||
print(f"⏱️ Step 5 execution time: {execution_time:.2f} seconds")
|
||||
|
||||
if result:
|
||||
print("✅ Step 5 executed successfully!")
|
||||
print(f"Status: {result.get('status', 'unknown')}")
|
||||
print(f"Quality Score: {result.get('quality_score', 0)}")
|
||||
print(f"Execution Time: {result.get('execution_time', 'unknown')}")
|
||||
|
||||
if result.get('status') == 'error':
|
||||
print(f"❌ Step 5 Error: {result.get('error_message', 'Unknown error')}")
|
||||
else:
|
||||
print("📊 Step 5 Results:")
|
||||
step_result = result.get('result', {})
|
||||
print(f" - Pillar Mapping: {step_result.get('pillarMapping', {}).get('distribution_balance', 0):.1%} balance")
|
||||
print(f" - Theme Development: {step_result.get('themeDevelopment', {}).get('variety_score', 0):.1%} variety")
|
||||
print(f" - Strategic Validation: {step_result.get('strategicValidation', {}).get('alignment_score', 0):.1%} alignment")
|
||||
print(f" - Diversity Assurance: {step_result.get('diversityAssurance', {}).get('diversity_score', 0):.1%} diversity")
|
||||
else:
|
||||
print("❌ Step 5 returned None")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error testing Step 5: {e}")
|
||||
import traceback
|
||||
print(f"📋 Traceback: {traceback.format_exc()}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(test_step5_orchestrator_direct())
|
||||
303
backend/test/test_steps_1_8.py
Normal file
303
backend/test/test_steps_1_8.py
Normal file
@@ -0,0 +1,303 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test Script for Steps 1-8 of Calendar Generation Framework
|
||||
|
||||
This script tests the first 8 steps of the calendar generation process
|
||||
with real data sources and no fallbacks.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
from typing import Dict, Any
|
||||
from loguru import logger
|
||||
|
||||
# Add the backend directory to the path
|
||||
backend_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
if backend_dir not in sys.path:
|
||||
sys.path.insert(0, backend_dir)
|
||||
|
||||
# Add the services directory to the path
|
||||
services_dir = os.path.join(backend_dir, "services")
|
||||
if services_dir not in sys.path:
|
||||
sys.path.insert(0, services_dir)
|
||||
|
||||
async def test_steps_1_8():
|
||||
"""Test Steps 1-8 of the calendar generation framework."""
|
||||
|
||||
try:
|
||||
logger.info("🚀 Starting test of Steps 1-8")
|
||||
|
||||
# Test data
|
||||
test_context = {
|
||||
"user_id": 1,
|
||||
"strategy_id": 1,
|
||||
"calendar_duration": 7, # 1 week
|
||||
"posting_preferences": {
|
||||
"posting_frequency": "daily",
|
||||
"preferred_days": ["monday", "wednesday", "friday"],
|
||||
"preferred_times": ["09:00", "12:00", "15:00"],
|
||||
"content_per_day": 2
|
||||
}
|
||||
}
|
||||
|
||||
# Test Step 1: Content Strategy Analysis
|
||||
logger.info("📋 Testing Step 1: Content Strategy Analysis")
|
||||
try:
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.steps.phase1.phase1_steps import ContentStrategyAnalysisStep
|
||||
from services.calendar_generation_datasource_framework.data_processing.strategy_data import StrategyDataProcessor
|
||||
|
||||
# Create strategy processor with mock data for testing
|
||||
strategy_processor = StrategyDataProcessor()
|
||||
|
||||
# For testing, we'll create a simple mock strategy data
|
||||
# In a real scenario, this would come from the database
|
||||
mock_strategy_data = {
|
||||
"strategy_id": 1,
|
||||
"strategy_name": "Test Strategy",
|
||||
"industry": "technology",
|
||||
"target_audience": {
|
||||
"primary": "Tech professionals",
|
||||
"secondary": "Business leaders",
|
||||
"demographics": {"age_range": "25-45", "location": "Global"}
|
||||
},
|
||||
"content_pillars": [
|
||||
"AI and Machine Learning",
|
||||
"Digital Transformation",
|
||||
"Innovation and Technology Trends",
|
||||
"Business Strategy and Growth"
|
||||
],
|
||||
"business_objectives": [
|
||||
"Increase brand awareness by 40%",
|
||||
"Generate 500 qualified leads per month",
|
||||
"Establish thought leadership"
|
||||
],
|
||||
"target_metrics": {"awareness": "website_traffic", "leads": "lead_generation"},
|
||||
"quality_indicators": {"data_completeness": 0.8, "strategic_alignment": 0.9}
|
||||
}
|
||||
|
||||
# Mock the get_strategy_data method for testing
|
||||
async def mock_get_strategy_data(strategy_id):
|
||||
return mock_strategy_data
|
||||
|
||||
strategy_processor.get_strategy_data = mock_get_strategy_data
|
||||
|
||||
# Mock the validate_data method
|
||||
async def mock_validate_data(data):
|
||||
return {
|
||||
"quality_score": 0.85,
|
||||
"missing_fields": [],
|
||||
"recommendations": []
|
||||
}
|
||||
|
||||
strategy_processor.validate_data = mock_validate_data
|
||||
|
||||
step1 = ContentStrategyAnalysisStep()
|
||||
step1.strategy_processor = strategy_processor
|
||||
|
||||
result1 = await step1.execute(test_context)
|
||||
logger.info(f"✅ Step 1 completed: {result1.get('status')}")
|
||||
logger.info(f" Quality Score: {result1.get('quality_score')}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Step 1 failed: {str(e)}")
|
||||
return False
|
||||
|
||||
# Test Step 2: Gap Analysis
|
||||
logger.info("📋 Testing Step 2: Gap Analysis")
|
||||
try:
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.steps.phase1.phase1_steps import GapAnalysisStep
|
||||
from services.calendar_generation_datasource_framework.data_processing.gap_analysis_data import GapAnalysisDataProcessor
|
||||
|
||||
# Create gap processor with mock data for testing
|
||||
gap_processor = GapAnalysisDataProcessor()
|
||||
|
||||
# Mock gap analysis data
|
||||
mock_gap_data = {
|
||||
"content_gaps": [
|
||||
{"topic": "AI Ethics", "priority": "high", "impact_score": 0.9},
|
||||
{"topic": "Digital Transformation ROI", "priority": "medium", "impact_score": 0.7},
|
||||
{"topic": "Cloud Migration Strategies", "priority": "high", "impact_score": 0.8}
|
||||
],
|
||||
"keyword_opportunities": [
|
||||
{"keyword": "AI ethics in business", "search_volume": 5000, "competition": "low"},
|
||||
{"keyword": "digital transformation ROI", "search_volume": 8000, "competition": "medium"},
|
||||
{"keyword": "cloud migration guide", "search_volume": 12000, "competition": "high"}
|
||||
],
|
||||
"competitor_insights": {
|
||||
"top_competitors": ["Competitor A", "Competitor B"],
|
||||
"content_gaps": ["AI Ethics", "Practical ROI"],
|
||||
"opportunities": ["Case Studies", "Implementation Guides"]
|
||||
},
|
||||
"opportunities": [
|
||||
{"type": "content", "topic": "AI Ethics", "priority": "high"},
|
||||
{"type": "content", "topic": "ROI Analysis", "priority": "medium"}
|
||||
],
|
||||
"recommendations": [
|
||||
"Create comprehensive AI ethics guide",
|
||||
"Develop ROI calculator for digital transformation",
|
||||
"Publish case studies on successful implementations"
|
||||
]
|
||||
}
|
||||
|
||||
# Mock the get_gap_analysis_data method
|
||||
async def mock_get_gap_analysis_data(user_id):
|
||||
return mock_gap_data
|
||||
|
||||
gap_processor.get_gap_analysis_data = mock_get_gap_analysis_data
|
||||
|
||||
step2 = GapAnalysisStep()
|
||||
step2.gap_processor = gap_processor
|
||||
|
||||
result2 = await step2.execute(test_context)
|
||||
logger.info(f"✅ Step 2 completed: {result2.get('status')}")
|
||||
logger.info(f" Quality Score: {result2.get('quality_score')}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Step 2 failed: {str(e)}")
|
||||
return False
|
||||
|
||||
# Test Step 3: Audience & Platform Strategy
|
||||
logger.info("📋 Testing Step 3: Audience & Platform Strategy")
|
||||
try:
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.steps.phase1.phase1_steps import AudiencePlatformStrategyStep
|
||||
from services.calendar_generation_datasource_framework.data_processing.comprehensive_user_data import ComprehensiveUserDataProcessor
|
||||
|
||||
# Create comprehensive processor with mock data for testing
|
||||
comprehensive_processor = ComprehensiveUserDataProcessor()
|
||||
|
||||
# Mock comprehensive user data
|
||||
mock_user_data = {
|
||||
"user_id": 1,
|
||||
"onboarding_data": {
|
||||
"industry": "technology",
|
||||
"business_size": "enterprise",
|
||||
"target_audience": {
|
||||
"primary": "Tech professionals",
|
||||
"secondary": "Business leaders",
|
||||
"demographics": {"age_range": "25-45", "location": "Global"}
|
||||
},
|
||||
"platform_preferences": {
|
||||
"LinkedIn": {"priority": "high", "content_focus": "professional"},
|
||||
"Twitter": {"priority": "medium", "content_focus": "news"},
|
||||
"Blog": {"priority": "high", "content_focus": "in-depth"}
|
||||
}
|
||||
},
|
||||
"performance_data": {
|
||||
"LinkedIn": {"engagement_rate": 0.08, "reach": 10000},
|
||||
"Twitter": {"engagement_rate": 0.05, "reach": 5000},
|
||||
"Blog": {"engagement_rate": 0.12, "reach": 8000}
|
||||
},
|
||||
"strategy_data": mock_strategy_data
|
||||
}
|
||||
|
||||
# Mock the get_comprehensive_user_data method
|
||||
async def mock_get_comprehensive_user_data(user_id, strategy_id):
|
||||
return mock_user_data
|
||||
|
||||
comprehensive_processor.get_comprehensive_user_data = mock_get_comprehensive_user_data
|
||||
|
||||
step3 = AudiencePlatformStrategyStep()
|
||||
step3.comprehensive_processor = comprehensive_processor
|
||||
|
||||
result3 = await step3.execute(test_context)
|
||||
logger.info(f"✅ Step 3 completed: {result3.get('status')}")
|
||||
logger.info(f" Quality Score: {result3.get('quality_score')}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Step 3 failed: {str(e)}")
|
||||
return False
|
||||
|
||||
# Test Step 4: Calendar Framework
|
||||
logger.info("📋 Testing Step 4: Calendar Framework")
|
||||
try:
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.steps.phase2.step4_implementation import CalendarFrameworkStep
|
||||
|
||||
step4 = CalendarFrameworkStep()
|
||||
result4 = await step4.execute(test_context)
|
||||
logger.info(f"✅ Step 4 completed: {result4.get('status')}")
|
||||
logger.info(f" Quality Score: {result4.get('quality_score')}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Step 4 failed: {str(e)}")
|
||||
return False
|
||||
|
||||
# Test Step 5: Content Pillar Distribution
|
||||
logger.info("📋 Testing Step 5: Content Pillar Distribution")
|
||||
try:
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.steps.phase2.step5_implementation import ContentPillarDistributionStep
|
||||
|
||||
step5 = ContentPillarDistributionStep()
|
||||
result5 = await step5.execute(test_context)
|
||||
logger.info(f"✅ Step 5 completed: {result5.get('status')}")
|
||||
logger.info(f" Quality Score: {result5.get('quality_score')}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Step 5 failed: {str(e)}")
|
||||
return False
|
||||
|
||||
# Test Step 6: Platform-Specific Strategy
|
||||
logger.info("📋 Testing Step 6: Platform-Specific Strategy")
|
||||
try:
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.steps.phase2.step6_implementation import PlatformSpecificStrategyStep
|
||||
|
||||
step6 = PlatformSpecificStrategyStep()
|
||||
result6 = await step6.execute(test_context)
|
||||
logger.info(f"✅ Step 6 completed: {result6.get('status')}")
|
||||
logger.info(f" Quality Score: {result6.get('quality_score')}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Step 6 failed: {str(e)}")
|
||||
return False
|
||||
|
||||
# Test Step 7: Weekly Theme Development
|
||||
logger.info("📋 Testing Step 7: Weekly Theme Development")
|
||||
try:
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.steps.phase3.step7_implementation import WeeklyThemeDevelopmentStep
|
||||
|
||||
step7 = WeeklyThemeDevelopmentStep()
|
||||
result7 = await step7.execute(test_context)
|
||||
logger.info(f"✅ Step 7 completed: {result7.get('status')}")
|
||||
logger.info(f" Quality Score: {result7.get('quality_score')}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Step 7 failed: {str(e)}")
|
||||
return False
|
||||
|
||||
# Test Step 8: Daily Content Planning
|
||||
logger.info("📋 Testing Step 8: Daily Content Planning")
|
||||
try:
|
||||
from services.calendar_generation_datasource_framework.prompt_chaining.steps.phase3.step8_implementation import DailyContentPlanningStep
|
||||
|
||||
step8 = DailyContentPlanningStep()
|
||||
result8 = await step8.execute(test_context)
|
||||
logger.info(f"✅ Step 8 completed: {result8.get('status')}")
|
||||
logger.info(f" Quality Score: {result8.get('quality_score')}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Step 8 failed: {str(e)}")
|
||||
return False
|
||||
|
||||
logger.info("🎉 All Steps 1-8 completed successfully!")
|
||||
logger.info("📝 Note: This test uses mock data for database services.")
|
||||
logger.info("📝 In production, real database services would be used.")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Test failed with error: {str(e)}")
|
||||
return False
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Configure logging
|
||||
logger.remove()
|
||||
logger.add(sys.stderr, level="INFO", format="<green>{time:HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>")
|
||||
|
||||
# Run the test
|
||||
success = asyncio.run(test_steps_1_8())
|
||||
|
||||
if success:
|
||||
logger.info("✅ Test completed successfully!")
|
||||
sys.exit(0)
|
||||
else:
|
||||
logger.error("❌ Test failed!")
|
||||
sys.exit(1)
|
||||
Reference in New Issue
Block a user