diff --git a/ToBeMigrated/utils/alwrity_utils.py b/ToBeMigrated/utils/alwrity_utils.py
deleted file mode 100644
index d8375f85..00000000
--- a/ToBeMigrated/utils/alwrity_utils.py
+++ /dev/null
@@ -1,232 +0,0 @@
-import re
-import os
-import PyPDF2
-import openai
-import streamlit as st
-import tempfile
-from loguru import logger
-
-
-from lib.ai_writers.ai_news_article_writer import ai_news_generation
-from lib.ai_writers.ai_finance_report_generator.ai_financial_dashboard import get_dashboard
-from lib.ai_writers.ai_facebook_writer.facebook_ai_writer import facebook_main_menu
-from lib.ai_writers.linkedin_writer.linkedin_ai_writer import linkedin_main_menu
-from lib.ai_writers.twitter_writers.twitter_dashboard import run_dashboard
-from lib.ai_writers.insta_ai_writer import insta_writer
-from lib.ai_writers.youtube_writers.youtube_ai_writer import youtube_main_menu
-from lib.ai_writers.ai_essay_writer import ai_essay_generator
-from lib.gpt_providers.text_to_image_generation.main_generate_image_from_prompt import generate_image
-#from lib.content_planning_calender.content_planning_agents_alwrity_crew import ai_agents_content_planner
-from lib.gpt_providers.text_generation.main_text_generation import llm_text_gen
-
-
-def ai_agents_team():
- # Define options for AI Content Teams
- st.title("π² Your AI Agents Teams")
- st.markdown("""Alwrity offers AI agents team for content creators to easily modify them for their needs.
- Abstracting tech & plumbing, easily define role, goal, task. Use different AI agents framework.""")
-
- options = [
- "AI Planning Team",
- "AI Content Creation Team"
- ]
-
- # Radio button for choosing an AI Content Team
- selected_team = st.radio("**Choose AI Agents Team:**", options)
-
- if selected_team == "AI Planning Team":
- st.title("AI Agents for Content Ideation")
- plan_keywords = st.text_input(
- "Enter Keywords to get 2 months content calendar:",
- placeholder="Enter keywords to generate AI content calendar:",
- help="Enter at least two words for better results."
- )
- if st.button("Get calendar"):
- if plan_keywords and len(plan_keywords.split()) >= 2:
- with st.spinner("Get Content Plan..."):
- try:
- #plan_content = ai_agents_content_planner(plan_keywords)
- st.success(f"Coming soon: Content plan for: {plan_keywords}")
- #st.markdown(plan_content)
- except Exception as err:
- st.error(f"Failed to generate content plan: {err}")
- else:
- st.error("π« Single keywords are just too vague. Try again.")
- elif selected_team == "AI Content Creation Team":
- content_agents()
-
-
-
-def content_agents():
- st.markdown("AI Agents Team for Content Writing")
- content_keywords = st.text_input(
- "Enter Main Domain Keywords of your business:",
- placeholder="Better keywords, Better content. Get keywords from Google search",
- help="These keywords define your main business sector, blogging niche, Industry, domain etc"
- )
-
- if st.button("Start Writing"):
- if content_keywords and len(content_keywords.split()) >= 2:
- with st.spinner("Generating Content..."):
- try:
- #calendar_content = ai_agents_writers(content_keywords)
- st.success(f"π« Not implemented yet: {content_keywords}")
- #st.markdown(calendar_content)
- except Exception as err:
- st.error(f"π« Failed to generate content with AI Agents: {err}")
- else:
- st.error("π« Single keywords are just too vague. Try again.")
-
-
-
-def essay_writer():
- st.title("AI Essay Writer π")
- st.write("Select your essay type, education level, and desired length, then let AI generate an essay for you. β¨")
-
- # Define essay types and education levels
- essay_types = [
- "π Argumentative - Forming an opinion via research. Building an evidence-based argument.",
- "π Expository - Knowledge of a topic. Communicating information clearly.",
- "βοΈ Narrative - Creative language use. Presenting a compelling narrative.",
- "π¨ Descriptive - Creative language use. Describing sensory details."
- ]
-
- education_levels = [
- "π« Primary School",
- "π« High School",
- "π College",
- "π Graduate School"
- ]
-
- # Define the options for number of pages
- num_pages_options = [
- "π Short Form (1-2 pages)",
- "ππ Medium Form (3-5 pages)",
- "πππ Long Form (6+ pages)"
- ]
-
- # Create columns for input fields
- col1, col2 = st.columns(2)
-
- with col1:
- # Ask the user for the title of the essay
- essay_title = st.text_input("π Essay Title", placeholder="Enter the title of your essay", help="Provide a clear and concise title for your essay.")
-
- # Ask the user for type of essay
- selected_essay_type = st.selectbox("π Type of Essay", options=essay_types, help="Choose the type of essay you want to write.")
-
- with col2:
- # Ask the user for level of education
- selected_education_level = st.selectbox("π Level of Education", options=education_levels, help="Choose your level of education.")
-
- # Ask the user for number of pages
- selected_num_pages = st.selectbox("π Number of Pages", options=num_pages_options, help="Select the length of your essay.")
-
- if st.button("π Generate Essay"):
- if essay_title:
- st.success("Generating your essay... β¨")
- ai_essay_generator(essay_title, selected_essay_type, selected_education_level, selected_num_pages)
- else:
- st.error("Please enter a valid title for your essay. π«")
-
-
-def ai_news_writer():
- """ AI News Writer """
- st.markdown("
π° AI News Writer ποΈ
", unsafe_allow_html=True)
-
- # Input for news keywords
- news_keywords = st.text_input(
- "**π Enter Keywords from News Headlines:**",
- placeholder="Describe the News article in 3-5 words. Enter main keywords describing the News Event:",
- help="Enter at least two words for better results."
- )
-
- if news_keywords and len(news_keywords.split()) < 2:
- st.error("π« News keywords should be at least two words long. Least, you can do..")
-
- # Selectbox for country and language
- countries = [
- ("es", "Spain"),
- ("vn", "Vietnam"),
- ("pk", "Pakistan"),
- ("in", "India"),
- ("de", "Germany"),
- ("cn", "China")
- ]
-
- languages = [
- ("en", "English"),
- ("es", "Spanish"),
- ("vi", "Vietnamese"),
- ("ar", "Arabic"),
- ("hi", "Hindi"),
- ("de", "German"),
- ("zh-cn", "Chinese")
- ]
-
- col1, col2 = st.columns(2)
- with col1:
- news_country = st.selectbox("**π Select Origin Country of News Event:**",
- countries, format_func=lambda x: x[1], help="Which country did the NEWS originate from ?")
- with col2:
- news_language = st.selectbox("**π£οΈ Select News Article Language to Search For:**",
- languages, format_func=lambda x: x[1], help="Language to output News Article in ?")
-
- if st.button("π° Generate News Report"):
- if news_keywords and len(news_keywords.split()) >= 2:
- with st.spinner("Generating News Report... β³"):
- try:
- news_report = ai_news_generation(news_keywords, news_country, news_language)
- st.success(f"Successfully generated news report on: {news_keywords} π")
- st.markdown(news_report)
- except Exception as err:
- st.error(f"Failed to generate news report: {err} β")
- else:
- st.error("Please enter valid keywords for the news report. π«")
-
-
-def ai_finance_ta_writer():
- st.markdown("
AI Financial Technical Analysis Writer
", unsafe_allow_html=True)
-
- ticker_symbol = st.text_input(
- "Enter Ticker Symbol for TA:",
- placeholder="Enter a valid Ticker Symbol (Examples: IBM, BABA, HDFCBANK.NS, TATAMOTORS.NS etc)",
- help="Be sure of the ticker symbol. Double-check it! Examples: IBM, BABA, HDFCBANK.NS, TATAMOTORS.NS"
- )
-
- if st.button("Generate TA Report"):
- if ticker_symbol:
- with st.spinner("Generating TA Report..."):
- try:
- # Get dashboard instance and generate technical analysis
- dashboard = get_dashboard()
- ta_report = dashboard.generate_technical_analysis(ticker_symbol)
- st.success(f"Successfully generated TA report for: {ticker_symbol}")
- st.markdown(ta_report)
- except Exception as err:
- st.error(f"π« Check ticker symbol: Failed to write Financial Technical Analysis. Error: {err}")
- else:
- st.error("π« Provide a valid Ticker Symbol. Don't waste my time.")
-
-def ai_social_writer():
- # Define social media platforms as radio buttons
- social_media_options = [
- ("facebook", "Facebook"),
- ("linkedin", "LinkedIn"),
- ("twitter", "Twitter"),
- ("instagram", "Instagram"),
- ("youtube", "YouTube")
- ]
-
- # Selectbox for choosing a platform
- selected_platform = st.radio("Choose a Social Media Platform:", social_media_options, format_func=lambda x: x[1])
- if "facebook" in selected_platform:
- facebook_main_menu()
- elif "linkedin" in selected_platform:
- linkedin_main_menu()
- elif "twitter" in selected_platform:
- run_dashboard()
- elif "instagram" in selected_platform:
- insta_writer()
- elif "youtube" in selected_platform:
- youtube_main_menu()
\ No newline at end of file
diff --git a/ToBeMigrated/utils/test_config_settings.py b/ToBeMigrated/utils/test_config_settings.py
deleted file mode 100644
index 316c0de9..00000000
--- a/ToBeMigrated/utils/test_config_settings.py
+++ /dev/null
@@ -1,310 +0,0 @@
-"""Test configuration settings page for ALwrity."""
-
-import streamlit as st
-from loguru import logger
-import asyncio
-from lib.web_crawlers.async_web_crawler import AsyncWebCrawlerService
-from pages.style_utils import (
- get_test_config_styles,
- get_glass_container,
- get_info_section,
- get_example_box,
- get_analysis_section,
- get_style_guide_html
-)
-import sys
-from lib.personalization.style_analyzer import StyleAnalyzer
-
-# Set page config - must be the first Streamlit command
-st.set_page_config(
- layout="wide",
- initial_sidebar_state="collapsed",
- menu_items={
- 'Get Help': None,
- 'Report a bug': None,
- 'About': None
- }
-)
-
-import yaml
-from pathlib import Path
-import os
-from loguru import logger
-from lib.utils.read_main_config_params import get_personalization_settings
-from lib.web_crawlers.crawl4ai_web_crawler import analyze_style
-
-# Configure logger
-logger.remove() # Remove default handler
-logger.add(
- "logs/test_config_settings.log",
- rotation="500 MB",
- retention="10 days",
- level="DEBUG",
- format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}",
- backtrace=True,
- diagnose=True
-)
-logger.add(
- sys.stdout,
- level="INFO",
- format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {message}"
-)
-
-# Apply CSS styles
-st.markdown(get_test_config_styles(), unsafe_allow_html=True)
-
-def load_website_url():
- """Load website URL from config file."""
- try:
- logger.debug("Loading website URL from config file")
- config_path = Path(os.environ["ALWRITY_CONFIG"])
- config = yaml.safe_load(config_path.read_text())
- url = config.get('website', {}).get('url', '')
- logger.info(f"Loaded website URL: {url}")
- return url
- except Exception as e:
- logger.error(f"Error loading website URL: {str(e)}", exc_info=True)
- return ''
-
-def display_style_analysis(analysis_results: dict):
- """Display the style analysis results in a structured format."""
- try:
- # Writing Style Section
- st.markdown("### π¨ Writing Style Analysis")
- writing_style = analysis_results.get("writing_style", {})
- writing_style_content = f"""
-
- """
- st.markdown(get_analysis_section("Recommended Settings", recommended_content), unsafe_allow_html=True)
-
- except Exception as e:
- logger.error(f"Error displaying style analysis: {str(e)}")
- st.error(f"Error displaying analysis results: {str(e)}")
-
-def render_test_config_settings():
- """Render the test configuration settings page."""
- try:
- logger.info("Starting to render test configuration settings")
-
- # Add back button at the top
- col1, col2 = st.columns([1, 3])
- with col1:
- if st.button("β Back to Personalization Setup"):
- logger.info("User clicked back to personalization setup")
- # Set session state for navigation
- st.session_state.current_step = 4
- st.session_state.next_step = "personalization_setup"
- # Navigate back to the main page where personalization setup is rendered
- st.switch_page("alwrity.py")
-
- # Title and description
- st.title("π¨ Find Your Style with ALwrity")
- st.markdown(get_glass_container(
- "
Enter a website URL or provide content samples to analyze your writing style and get personalized recommendations.
"
- ), unsafe_allow_html=True)
-
- # Create two columns for the layout
- col1, col2 = st.columns([2, 1])
-
- with col1:
- # Website URL input
- st.markdown("### Website URL")
- url = st.text_input(
- "Enter your website URL",
- placeholder="https://example.com",
- help="Provide your website URL to analyze your content style. Leave empty if you want to provide written samples instead."
- )
- logger.debug(f"Website URL input value: {url}")
-
- # Alternative: Written samples
- if not url:
- st.markdown("### Written Samples")
- st.markdown(get_info_section("""
-
No website URL? No problem! You can provide written samples of your content instead.
-
Share your best articles, blog posts, or any content that represents your writing style.
- """), unsafe_allow_html=True)
- samples = st.text_area(
- "Paste your content samples here",
- help="Paste 2-3 samples of your best content. This helps ALwrity understand your writing style."
- )
- logger.debug(f"Sample text length: {len(samples) if samples else 0}")
-
- st.markdown('', unsafe_allow_html=True)
-
- # ALwrity Style button
- st.markdown("", unsafe_allow_html=True)
- if st.button("π¨ ALwrity Style", use_container_width=True):
- if url:
- with st.status("Starting style analysis...", expanded=True) as status:
- try:
- logger.info(f"Starting style analysis for URL: {url}")
-
- # Step 1: Initialize crawler
- status.update(label="Step 1/4: Initializing web crawler...", state="running")
- crawler_service = AsyncWebCrawlerService()
-
- # Step 2: Crawl website
- status.update(label="Step 2/4: Crawling website content...", state="running")
- loop = asyncio.new_event_loop()
- asyncio.set_event_loop(loop)
- result = loop.run_until_complete(crawler_service.crawl_website(url))
- loop.close()
-
- if result.get('success', False):
- content = result.get('content', {})
-
- # Step 3: Initialize style analyzer
- status.update(label="Step 3/4: Analyzing content style...", state="running")
- style_analyzer = StyleAnalyzer()
-
- # Step 4: Perform style analysis
- status.update(label="Step 4/4: Generating style recommendations...", state="running")
- style_analysis = style_analyzer.analyze_content_style(content)
-
- if style_analysis.get('error'):
- status.update(label="Analysis failed", state="error")
- st.error(f"Style analysis failed: {style_analysis['error']}")
- else:
- status.update(label="Analysis complete!", state="complete")
- # Display style analysis results
- display_style_analysis(style_analysis)
-
- # Display original content in tabs
- tab1, tab2, tab3 = st.tabs(["Content", "Metadata", "Links"])
-
- with tab1:
- st.markdown("### Main Content")
- st.markdown(content.get('main_content', 'No content found'))
-
- with tab2:
- st.markdown("### Metadata")
- st.markdown(f"""
- **Title:** {content.get('title', 'No title found')}
-
- **Description:** {content.get('description', 'No description found')}
-
- **Meta Tags:**
- {content.get('meta_tags', {})}
- """)
-
- with tab3:
- st.markdown("### Links")
- for link in content.get('links', []):
- st.markdown(f"- [{link.get('text', '')}]({link.get('href', '')})")
-
- else:
- status.update(label="Crawling failed", state="error")
- st.error(f"Failed to analyze website: {result.get('error', 'Unknown error')}")
-
- except Exception as e:
- logger.error(f"Error during style analysis: {str(e)}")
- st.error(f"Analysis failed: {str(e)}")
- elif samples:
- with st.spinner("Analyzing content samples..."):
- try:
- # TODO: Implement sample text analysis
- st.info("Sample text analysis coming soon!")
- except Exception as e:
- logger.error(f"Error analyzing samples: {str(e)}")
- st.error(f"Analysis failed: {str(e)}")
- else:
- st.warning("Please provide either a website URL or content samples")
-
- with col2:
- st.markdown("""
- ### How ALwrity Discovers Your Style
-
- **AI-Powered Style Analysis**
-
- ALwrity AI analyzes your existing content to understand your unique writing style and preferences. This helps us generate content that matches your voice perfectly.
-
- **Step 1: Content Analysis**
-
- We'll analyze your website content or written samples to understand:
-
- - Writing tone and voice
- - Vocabulary and language style
- - Content structure and formatting
- - Target audience and engagement style
-
- **Step 2: Style Recommendations**
-
- Based on the analysis, we'll provide:
-
- - Personalized writing guidelines
- - Content structure templates
- - Tone and voice recommendations
- - Audience engagement strategies
-
- **Step 3: Content Generation**
-
- Finally, we'll use these insights to:
-
- - Generate content that matches your style
- - Maintain consistency across all content
- - Optimize for your target audience
- - Ensure brand voice alignment
- """)
-
- except Exception as e:
- logger.error(f"Error in render_test_config_settings: {str(e)}")
- st.error(f"An error occurred: {str(e)}")
-
-if __name__ == "__main__":
- logger.info("Starting test config settings page")
- render_test_config_settings()
- logger.info("Test config settings page rendered successfully")
\ No newline at end of file
diff --git a/ToBeMigrated/utils/voice_processing.py b/ToBeMigrated/utils/voice_processing.py
deleted file mode 100644
index 912dfced..00000000
--- a/ToBeMigrated/utils/voice_processing.py
+++ /dev/null
@@ -1,23 +0,0 @@
-import streamlit as st
-from streamlit_mic_recorder import speech_to_text
-
-def record_voice(language="en"):
- # https://github.com/B4PT0R/streamlit-mic-recorder?tab=readme-ov-file#example
- state = st.session_state
- if "text_received" not in state:
- state.text_received = []
-
- text = speech_to_text(
- start_prompt="ποΈPress & Speakπ",
- stop_prompt="πStop Recordingπ¨",
- language=language,
- use_container_width=True,
- just_once=False,
- )
- if text:
- state.text_received.append(text)
- result = ""
- for text in state.text_received:
- result += text
- state.text_received = []
- return result if result else None
diff --git a/ToBeMigrated/utils/website_analyzer/models.py b/ToBeMigrated/utils/website_analyzer/models.py
deleted file mode 100644
index b5b55054..00000000
--- a/ToBeMigrated/utils/website_analyzer/models.py
+++ /dev/null
@@ -1,45 +0,0 @@
-"""Data models for website analysis results."""
-
-from dataclasses import dataclass
-from typing import List, Dict, Optional
-from datetime import datetime
-
-@dataclass
-class SEORecommendation:
- """A single SEO recommendation."""
- priority: str # 'high', 'medium', 'low'
- category: str # 'content', 'technical', 'meta', etc.
- issue: str
- recommendation: str
- impact: str
-
-@dataclass
-class MetaTagAnalysis:
- """Analysis of meta tags."""
- title: Dict[str, str] # {'status': 'good', 'value': 'actual title', 'recommendation': 'suggestion'}
- description: Dict[str, str]
- keywords: Dict[str, str]
- has_robots: bool
- has_sitemap: bool
-
-@dataclass
-class ContentAnalysis:
- """Analysis of page content."""
- word_count: int
- headings_structure: Dict[str, int] # {'h1': 1, 'h2': 3, etc}
- keyword_density: Dict[str, float]
- readability_score: float
- content_quality_score: float
-
-@dataclass
-class SEOAnalysisResult:
- """Complete SEO analysis result."""
- url: str
- analyzed_at: datetime
- overall_score: float # 0-100
- meta_tags: MetaTagAnalysis
- content: ContentAnalysis
- recommendations: List[SEORecommendation]
- errors: List[str]
- warnings: List[str]
- success: bool
\ No newline at end of file
diff --git a/backend/api/content_planning/api/content_strategy/endpoints/ai_generation_endpoints.py b/backend/api/content_planning/api/content_strategy/endpoints/ai_generation_endpoints.py
index d75bbb3e..1df7e533 100644
--- a/backend/api/content_planning/api/content_strategy/endpoints/ai_generation_endpoints.py
+++ b/backend/api/content_planning/api/content_strategy/endpoints/ai_generation_endpoints.py
@@ -8,8 +8,6 @@ from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from loguru import logger
from datetime import datetime
-from fastapi.responses import StreamingResponse
-import json
# Import database
from services.database import get_db_session
@@ -19,6 +17,9 @@ from ....services.content_strategy.ai_generation import AIStrategyGenerator, Str
from ....services.enhanced_strategy_service import EnhancedStrategyService
from ....services.enhanced_strategy_db_service import EnhancedStrategyDBService
+# Import educational content manager
+from .content_strategy.educational_content import EducationalContentManager
+
# Import utilities
from ....utils.error_handlers import ContentPlanningErrorHandler
from ....utils.response_builders import ResponseBuilder
@@ -34,6 +35,9 @@ def get_db():
finally:
db.close()
+# Global storage for latest strategies (more persistent than task status)
+_latest_strategies = {}
+
@router.post("/generate-comprehensive-strategy")
async def generate_comprehensive_strategy(
user_id: int,
@@ -302,427 +306,194 @@ async def optimize_existing_strategy(
logger.error(f"β Error optimizing strategy: {str(e)}")
raise ContentPlanningErrorHandler.handle_general_error(e, "optimize_existing_strategy")
-@router.get("/generate-comprehensive-strategy/stream")
-async def generate_comprehensive_strategy_stream(
- user_id: int,
- strategy_name: Optional[str] = None,
- config: Optional[Dict[str, Any]] = None,
+@router.post("/generate-comprehensive-strategy-polling")
+async def generate_comprehensive_strategy_polling(
+ request: Dict[str, Any],
db: Session = Depends(get_db)
-):
- """Generate comprehensive AI strategy with Server-Sent Events for progress updates."""
+) -> Dict[str, Any]:
+ """Generate a comprehensive AI-powered content strategy using polling approach."""
try:
- logger.info(f"π Starting streaming AI strategy generation for user: {user_id}")
+ # Extract parameters from request body
+ user_id = request.get("user_id", 1)
+ strategy_name = request.get("strategy_name")
+ config = request.get("config", {})
- async def generate_strategy_stream():
- try:
- # Step 1: Get user context with educational content
- yield f"data: {json.dumps({
- 'step': 1,
- 'message': 'Getting user context...',
- 'progress': 10,
- 'educational_content': {
- 'title': 'π Analyzing Your Data',
- 'description': 'We\'re gathering all your onboarding information to create a personalized strategy.',
- 'details': [
- 'π Website analysis data',
- 'π― Research preferences',
- 'π API configurations',
- 'π Historical performance metrics'
- ],
- 'insight': 'Your data helps us understand your business context, target audience, and competitive landscape.',
- 'ai_prompt_preview': 'Analyzing user onboarding data to extract business context, audience insights, and competitive positioning...'
- }
- })}\n\n"
+ logger.info(f"π Starting polling-based AI strategy generation for user: {user_id}")
+
+ # Get user context and onboarding data
+ db_service = EnhancedStrategyDBService(db)
+ enhanced_service = EnhancedStrategyService(db_service)
+
+ # Get onboarding data for context
+ onboarding_data = await enhanced_service._get_onboarding_data(user_id)
- db_service = EnhancedStrategyDBService(db)
- enhanced_service = EnhancedStrategyService(db_service)
- onboarding_data = await enhanced_service._get_onboarding_data(user_id)
-
- context = {
+ # Build context for AI generation
+ context = {
"onboarding_data": onboarding_data,
"user_id": user_id,
"generation_config": config or {}
}
- # Step 2: Generate base strategy fields
- yield f"data: {json.dumps({
- 'step': 2,
- 'message': 'Generating base strategy fields...',
- 'progress': 20,
- 'educational_content': {
- 'title': 'ποΈ Building Foundation',
- 'description': 'Creating the core strategy framework based on your business objectives.',
- 'details': [
- 'π― Business objectives mapping',
- 'π Target metrics definition',
- 'π° Budget allocation strategy',
- 'β° Timeline planning'
- ],
- 'insight': 'A solid foundation ensures your content strategy aligns with business goals and resources.',
- 'ai_prompt_preview': 'Generating strategic foundation: business objectives, target metrics, budget allocation, and timeline planning...'
- }
- })}\n\n"
+ # Create strategy generation config
+ generation_config = StrategyGenerationConfig(
+ include_competitive_analysis=config.get("include_competitive_analysis", True) if config else True,
+ include_content_calendar=config.get("include_content_calendar", True) if config else True,
+ include_performance_predictions=config.get("include_performance_predictions", True) if config else True,
+ include_implementation_roadmap=config.get("include_implementation_roadmap", True) if config else True,
+ include_risk_assessment=config.get("include_risk_assessment", True) if config else True,
+ max_content_pieces=config.get("max_content_pieces", 50) if config else 50,
+ timeline_months=config.get("timeline_months", 12) if config else 12
+ )
# Initialize AI strategy generator
- from ....services.content_strategy.ai_generation import AIStrategyGenerator
- strategy_generator = AIStrategyGenerator()
+ strategy_generator = AIStrategyGenerator(generation_config)
+
+ # Start generation in background (non-blocking)
+ import asyncio
+ import uuid
+
+ # Generate unique task ID
+ task_id = str(uuid.uuid4())
+
+ # Store initial status
+ generation_status = {
+ "task_id": task_id,
+ "user_id": user_id,
+ "status": "started",
+ "progress": 0,
+ "step": 0,
+ "message": "Initializing AI strategy generation...",
+ "started_at": datetime.utcnow().isoformat(),
+ "estimated_completion": None,
+ "strategy": None,
+ "error": None,
+ "educational_content": EducationalContentManager.get_initialization_content()
+ }
+
+ # Store status in memory (in production, use Redis or database)
+ if not hasattr(generate_comprehensive_strategy_polling, '_task_status'):
+ generate_comprehensive_strategy_polling._task_status = {}
+
+ generate_comprehensive_strategy_polling._task_status[task_id] = generation_status
+
+ # Start background task
+ async def generate_strategy_background():
+ try:
+ logger.info(f"π Starting background strategy generation for task: {task_id}")
- # Step 3: Generate strategic insights with real-time educational content
- yield f"data: {json.dumps({
- 'step': 3,
- 'message': 'Generating strategic insights...',
- 'progress': 30,
- 'educational_content': {
- 'title': 'π§ Strategic Intelligence Analysis',
- 'description': 'AI is analyzing your market position and identifying strategic opportunities.',
- 'details': [
- 'π― Market positioning analysis',
- 'π‘ Opportunity identification',
- 'π Growth potential assessment',
- 'πͺ Competitive advantage mapping'
- ],
- 'insight': 'Strategic insights help you understand where you stand in the market and how to differentiate.',
- 'ai_prompt_preview': 'Analyzing market position, identifying strategic opportunities, assessing growth potential, and mapping competitive advantages...',
- 'estimated_time': '15-20 seconds'
- }
- })}\n\n"
+ # Step 1: Get user context
+ generate_comprehensive_strategy_polling._task_status[task_id].update({
+ "step": 1,
+ "progress": 10,
+ "message": "Getting user context...",
+ "educational_content": EducationalContentManager.get_step_content(1)
+ })
- try:
- # Create a custom AI service manager that emits educational content to SSE
- from services.ai_service_manager import AIServiceManager, AIServiceType
-
- class SSEAIServiceManager(AIServiceManager):
- def __init__(self, sse_yield_func):
- super().__init__()
- self.sse_yield = sse_yield_func
-
- async def _emit_educational_content(self, service_type: AIServiceType, status: str, error_message: str = None, processing_time: float = None):
- """Override to emit educational content to SSE stream."""
- try:
- educational_content = self._get_educational_content(service_type, status, error_message, processing_time)
-
- # Emit to SSE stream
- yield_data = {
- 'type': 'educational_content',
- 'service_type': service_type.value,
- 'status': status,
- 'educational_content': educational_content
- }
-
- if processing_time:
- yield_data['processing_time'] = processing_time
- if error_message:
- yield_data['error_message'] = error_message
-
- await self.sse_yield(f"data: {json.dumps(yield_data)}\n\n")
- logger.info(f"π Emitted educational content for {service_type.value}: {status}")
-
- except Exception as e:
- logger.error(f"Error emitting educational content to SSE: {e}")
-
- # Use the SSE-enabled AI service manager
- sse_ai_manager = SSEAIServiceManager(lambda data: generate_strategy_stream().__anext__())
-
- # Generate strategic insights with educational content
- strategic_insights = await strategy_generator._generate_strategic_insights({}, context, sse_ai_manager)
-
- yield f"data: {json.dumps({
- 'step': 3,
- 'message': 'Strategic insights generated successfully',
- 'progress': 35,
- 'success': True,
- 'educational_content': {
- 'title': 'β Strategic Insights Complete',
- 'description': 'Successfully identified key strategic opportunities and market positioning.',
- 'achievement': f'Generated {len(strategic_insights.get("insights", []))} strategic insights',
- 'next_step': 'Moving to competitive analysis...'
- }
- })}\n\n"
- except Exception as e:
- yield f"data: {json.dumps({
- 'step': 3,
- 'message': f'Strategic insights generation failed: {str(e)}',
- 'progress': 35,
- 'success': False,
- 'error': str(e),
- 'educational_content': {
- 'title': 'β οΈ Strategic Insights Issue',
- 'description': 'We encountered an issue with strategic analysis, but continuing with other components.',
- 'fallback': 'Will use industry best practices for strategic positioning.'
- }
- })}\n\n"
- strategic_insights = {}
+ # Step 2: Generate base strategy fields
+ generate_comprehensive_strategy_polling._task_status[task_id].update({
+ "step": 2,
+ "progress": 20,
+ "message": "Generating base strategy fields...",
+ "educational_content": EducationalContentManager.get_step_content(2)
+ })
- # Step 4: Generate competitive analysis with educational content
- yield f"data: {json.dumps({
- 'step': 4,
- 'message': 'Generating competitive analysis...',
- 'progress': 40,
- 'educational_content': {
- 'title': 'π Competitive Intelligence Analysis',
- 'description': 'AI is analyzing your competitors to identify gaps and opportunities.',
- 'details': [
- 'π’ Competitor content strategies',
- 'π Market gap analysis',
- 'π― Differentiation opportunities',
- 'π Industry trend analysis'
- ],
- 'insight': 'Understanding your competitors helps you find unique angles and underserved market segments.',
- 'ai_prompt_preview': 'Analyzing competitor content strategies, identifying market gaps, finding differentiation opportunities, and assessing industry trends...',
- 'estimated_time': '20-25 seconds'
- }
- })}\n\n"
+ # Step 3: Generate strategic insights
+ generate_comprehensive_strategy_polling._task_status[task_id].update({
+ "step": 3,
+ "progress": 30,
+ "message": "Generating strategic insights...",
+ "educational_content": EducationalContentManager.get_step_content(3)
+ })
- try:
- competitive_analysis = await strategy_generator._generate_competitive_analysis({}, context, sse_ai_manager)
- yield f"data: {json.dumps({
- 'step': 4,
- 'message': 'Competitive analysis generated successfully',
- 'progress': 45,
- 'success': True,
- 'educational_content': {
- 'title': 'β Competitive Analysis Complete',
- 'description': 'Successfully analyzed competitive landscape and identified market opportunities.',
- 'achievement': f'Analyzed {len(competitive_analysis.get("competitors", []))} competitors',
- 'next_step': 'Moving to content calendar generation...'
- }
- })}\n\n"
- except Exception as e:
- yield f"data: {json.dumps({
- 'step': 4,
- 'message': f'Competitive analysis generation failed: {str(e)}',
- 'progress': 45,
- 'success': False,
- 'error': str(e),
- 'educational_content': {
- 'title': 'β οΈ Competitive Analysis Issue',
- 'description': 'We encountered an issue with competitive analysis, but continuing with other components.',
- 'fallback': 'Will use industry best practices for competitive positioning.'
- }
- })}\n\n"
- competitive_analysis = {}
+ strategic_insights = await strategy_generator._generate_strategic_insights({}, context)
- # Step 5: Generate content calendar with educational content
- yield f"data: {json.dumps({
- 'step': 5,
- 'message': 'Generating content calendar...',
- 'progress': 50,
- 'educational_content': {
- 'title': 'π Content Calendar Creation',
- 'description': 'AI is building a comprehensive content schedule optimized for your audience.',
- 'details': [
- 'π Content piece generation',
- 'π Optimal publishing schedule',
- 'π― Audience engagement timing',
- 'π Content repurposing strategy'
- ],
- 'insight': 'A well-planned content calendar ensures consistent engagement and maximizes content ROI.',
- 'ai_prompt_preview': 'Generating content pieces, optimizing publishing schedule, determining audience engagement timing, and planning content repurposing...',
- 'estimated_time': '25-30 seconds'
- }
- })}\n\n"
+ generate_comprehensive_strategy_polling._task_status[task_id].update({
+ "step": 3,
+ "progress": 35,
+ "message": "Strategic insights generated successfully",
+ "educational_content": EducationalContentManager.get_step_completion_content(3, strategic_insights)
+ })
- try:
- content_calendar = await strategy_generator._generate_content_calendar({}, context, sse_ai_manager)
- yield f"data: {json.dumps({
- 'step': 5,
- 'message': 'Content calendar generated successfully',
- 'progress': 55,
- 'success': True,
- 'educational_content': {
- 'title': 'β Content Calendar Complete',
- 'description': 'Successfully created comprehensive content schedule.',
- 'achievement': f'Generated {len(content_calendar.get("content_pieces", []))} content pieces',
- 'next_step': 'Moving to performance predictions...'
- }
- })}\n\n"
- except Exception as e:
- yield f"data: {json.dumps({
- 'step': 5,
- 'message': f'Content calendar generation failed: {str(e)}',
- 'progress': 55,
- 'success': False,
- 'error': str(e),
- 'educational_content': {
- 'title': 'β οΈ Content Calendar Issue',
- 'description': 'We encountered an issue with content calendar generation, but continuing with other components.',
- 'fallback': 'Will use industry best practices for content scheduling.'
- }
- })}\n\n"
- content_calendar = {}
+ # Step 4: Generate competitive analysis
+ generate_comprehensive_strategy_polling._task_status[task_id].update({
+ "step": 4,
+ "progress": 40,
+ "message": "Generating competitive analysis...",
+ "educational_content": EducationalContentManager.get_step_content(4)
+ })
- # Step 6: Generate performance predictions with educational content
- yield f"data: {json.dumps({
- 'step': 6,
- 'message': 'Generating performance predictions...',
- 'progress': 60,
- 'educational_content': {
- 'title': 'π Performance Forecasting',
- 'description': 'AI is predicting content performance and ROI based on industry data.',
- 'details': [
- 'π Traffic growth projections',
- 'π° ROI predictions',
- 'π― Conversion rate estimates',
- 'π Engagement metrics forecasting'
- ],
- 'insight': 'Performance predictions help you set realistic expectations and optimize resource allocation.',
- 'ai_prompt_preview': 'Analyzing industry benchmarks, predicting traffic growth, estimating ROI, forecasting conversion rates, and projecting engagement metrics...',
- 'estimated_time': '15-20 seconds'
- }
- })}\n\n"
+ competitive_analysis = await strategy_generator._generate_competitive_analysis({}, context)
- try:
- performance_predictions = await strategy_generator._generate_performance_predictions({}, context, sse_ai_manager)
- yield f"data: {json.dumps({
- 'step': 6,
- 'message': 'Performance predictions generated successfully',
- 'progress': 65,
- 'success': True,
- 'educational_content': {
- 'title': 'β Performance Predictions Complete',
- 'description': 'Successfully predicted content performance and ROI.',
- 'achievement': f'Predicted {performance_predictions.get("estimated_roi", "15-25%")} ROI',
- 'next_step': 'Moving to implementation roadmap...'
- }
- })}\n\n"
- except Exception as e:
- yield f"data: {json.dumps({
- 'step': 6,
- 'message': f'Performance predictions generation failed: {str(e)}',
- 'progress': 65,
- 'success': False,
- 'error': str(e),
- 'educational_content': {
- 'title': 'β οΈ Performance Predictions Issue',
- 'description': 'We encountered an issue with performance predictions, but continuing with other components.',
- 'fallback': 'Will use industry benchmarks for performance estimates.'
- }
- })}\n\n"
- performance_predictions = {}
+ generate_comprehensive_strategy_polling._task_status[task_id].update({
+ "step": 4,
+ "progress": 45,
+ "message": "Competitive analysis generated successfully",
+ "educational_content": EducationalContentManager.get_step_completion_content(4, competitive_analysis)
+ })
- # Step 7: Generate implementation roadmap with educational content
- yield f"data: {json.dumps({
- 'step': 7,
- 'message': 'Generating implementation roadmap...',
- 'progress': 70,
- 'educational_content': {
- 'title': 'πΊοΈ Implementation Roadmap',
- 'description': 'AI is creating a detailed implementation plan for your content strategy.',
- 'details': [
- 'π Task breakdown and timeline',
- 'π₯ Resource allocation planning',
- 'π― Milestone definition',
- 'π Success metric tracking'
- ],
- 'insight': 'A clear implementation roadmap ensures successful strategy execution and measurable results.',
- 'ai_prompt_preview': 'Creating implementation roadmap: task breakdown, resource allocation, milestone planning, and success metric definition...',
- 'estimated_time': '15-20 seconds'
- }
- })}\n\n"
+ # Step 5: Generate performance predictions
+ generate_comprehensive_strategy_polling._task_status[task_id].update({
+ "step": 4,
+ "progress": 40,
+ "message": "Generating performance predictions...",
+ "educational_content": EducationalContentManager.get_step_content(4)
+ })
- try:
- implementation_roadmap = await strategy_generator._generate_implementation_roadmap({}, context, sse_ai_manager)
- yield f"data: {json.dumps({
- 'step': 7,
- 'message': 'Implementation roadmap generated successfully',
- 'progress': 75,
- 'success': True,
- 'educational_content': {
- 'title': 'β Implementation Roadmap Complete',
- 'description': 'Successfully created detailed implementation plan.',
- 'achievement': f'Planned {implementation_roadmap.get("total_duration", "12 months")} implementation timeline',
- 'next_step': 'Moving to risk assessment...'
- }
- })}\n\n"
- except Exception as e:
- yield f"data: {json.dumps({
- 'step': 7,
- 'message': f'Implementation roadmap generation failed: {str(e)}',
- 'progress': 75,
- 'success': False,
- 'error': str(e),
- 'educational_content': {
- 'title': 'β οΈ Implementation Roadmap Issue',
- 'description': 'We encountered an issue with implementation roadmap generation, but continuing with other components.',
- 'fallback': 'Will use industry best practices for implementation planning.'
- }
- })}\n\n"
- implementation_roadmap = {}
+ performance_predictions = await strategy_generator._generate_performance_predictions({}, context)
- # Step 8: Generate risk assessment with educational content
- yield f"data: {json.dumps({
- 'step': 8,
- 'message': 'Generating risk assessment...',
- 'progress': 80,
- 'educational_content': {
- 'title': 'β οΈ Risk Assessment',
- 'description': 'AI is identifying potential risks and mitigation strategies for your content strategy.',
- 'details': [
- 'π Risk identification and analysis',
- 'π Risk probability assessment',
- 'π‘οΈ Mitigation strategy development',
- 'π Risk monitoring framework'
- ],
- 'insight': 'Proactive risk assessment helps you prepare for challenges and maintain strategy effectiveness.',
- 'ai_prompt_preview': 'Assessing risks: identifying potential challenges, analyzing probability and impact, developing mitigation strategies, and creating monitoring framework...',
- 'estimated_time': '10-15 seconds'
- }
- })}\n\n"
+ generate_comprehensive_strategy_polling._task_status[task_id].update({
+ "step": 4,
+ "progress": 45,
+ "message": "Performance predictions generated successfully",
+ "educational_content": EducationalContentManager.get_step_completion_content(4, performance_predictions)
+ })
- try:
- risk_assessment = await strategy_generator._generate_risk_assessment({}, context, sse_ai_manager)
- yield f"data: {json.dumps({
- 'step': 8,
- 'message': 'Risk assessment generated successfully',
- 'progress': 85,
- 'success': True,
- 'educational_content': {
- 'title': 'β Risk Assessment Complete',
- 'description': 'Successfully identified risks and mitigation strategies.',
- 'achievement': f'Assessed {risk_assessment.get("overall_risk_level", "Medium")} risk level',
- 'next_step': 'Finalizing comprehensive strategy...'
- }
- })}\n\n"
- except Exception as e:
- yield f"data: {json.dumps({
- 'step': 8,
- 'message': f'Risk assessment generation failed: {str(e)}',
- 'progress': 85,
- 'success': False,
- 'error': str(e),
- 'educational_content': {
- 'title': 'β οΈ Risk Assessment Issue',
- 'description': 'We encountered an issue with risk assessment, but continuing with strategy finalization.',
- 'fallback': 'Will use industry best practices for risk management.'
- }
- })}\n\n"
- risk_assessment = {}
+ # Step 5: Generate implementation roadmap
+ generate_comprehensive_strategy_polling._task_status[task_id].update({
+ "step": 5,
+ "progress": 50,
+ "message": "Generating implementation roadmap...",
+ "educational_content": EducationalContentManager.get_step_content(5)
+ })
- # Step 9: Compile comprehensive strategy
- yield f"data: {json.dumps({
- 'step': 9,
- 'message': 'Compiling comprehensive strategy...',
- 'progress': 90,
- 'educational_content': {
- 'title': 'π Strategy Compilation',
- 'description': 'AI is compiling all components into a comprehensive content strategy.',
- 'details': [
- 'π Component integration',
- 'π Data synthesis',
- 'π Strategy documentation',
- 'β Quality validation'
- ],
- 'insight': 'A comprehensive strategy integrates all components into a cohesive, actionable plan.',
- 'ai_prompt_preview': 'Compiling comprehensive strategy: integrating all components, synthesizing data, documenting strategy, and validating quality...',
- 'estimated_time': '5-10 seconds'
- }
- })}\n\n"
+ implementation_roadmap = await strategy_generator._generate_implementation_roadmap({}, context)
- # Compile the comprehensive strategy
+ generate_comprehensive_strategy_polling._task_status[task_id].update({
+ "step": 5,
+ "progress": 55,
+ "message": "Implementation roadmap generated successfully",
+ "educational_content": EducationalContentManager.get_step_completion_content(5, implementation_roadmap)
+ })
+
+ # Step 6: Generate risk assessment
+ generate_comprehensive_strategy_polling._task_status[task_id].update({
+ "step": 6,
+ "progress": 60,
+ "message": "Generating risk assessment...",
+ "educational_content": EducationalContentManager.get_step_content(6)
+ })
+
+ risk_assessment = await strategy_generator._generate_risk_assessment({}, context)
+
+ generate_comprehensive_strategy_polling._task_status[task_id].update({
+ "step": 6,
+ "progress": 65,
+ "message": "Risk assessment generated successfully",
+ "educational_content": EducationalContentManager.get_step_completion_content(6, risk_assessment)
+ })
+
+ # Step 7: Compile comprehensive strategy
+ generate_comprehensive_strategy_polling._task_status[task_id].update({
+ "step": 7,
+ "progress": 70,
+ "message": "Compiling comprehensive strategy...",
+ "educational_content": EducationalContentManager.get_step_content(7)
+ })
+
+ # Compile the comprehensive strategy (NO CONTENT CALENDAR)
comprehensive_strategy = {
"strategic_insights": strategic_insights,
"competitive_analysis": competitive_analysis,
- "content_calendar": content_calendar,
"performance_predictions": performance_predictions,
"implementation_roadmap": implementation_roadmap,
"risk_assessment": risk_assessment,
@@ -731,265 +502,226 @@ async def generate_comprehensive_strategy_stream(
"comprehensive": True,
"generation_timestamp": datetime.utcnow().isoformat(),
"user_id": user_id,
- "strategy_name": strategy_name or "Enhanced Content Strategy"
+ "strategy_name": strategy_name or "Enhanced Content Strategy",
+ "content_calendar_ready": False # Indicates calendar needs to be generated separately
}
}
- # Step 10: Complete with educational content
- yield f"data: {json.dumps({
- 'step': 10,
- 'message': 'Strategy generation completed successfully!',
- 'progress': 100,
- 'success': True,
- 'strategy': comprehensive_strategy,
- 'educational_content': {
- 'title': 'π Strategy Generation Complete!',
- 'description': 'Your comprehensive AI-powered content strategy is ready!',
- 'summary': {
- 'total_components': 6,
- 'successful_components': sum([
- 1 if strategic_insights else 0,
- 1 if competitive_analysis else 0,
- 1 if content_calendar else 0,
- 1 if performance_predictions else 0,
- 1 if implementation_roadmap else 0,
- 1 if risk_assessment else 0
- ]),
- 'total_content_pieces': len(content_calendar.get("content_pieces", [])),
- 'estimated_roi': performance_predictions.get("estimated_roi", "15-25%"),
- 'implementation_timeline': implementation_roadmap.get("total_duration", "12 months"),
- 'risk_level': risk_assessment.get("overall_risk_level", "Medium")
- },
- 'key_achievements': [
- 'π§ Strategic insights generated',
- 'π Competitive analysis completed',
- 'π Content calendar created',
- 'π Performance predictions calculated',
- 'πΊοΈ Implementation roadmap planned',
- 'β οΈ Risk assessment conducted'
- ],
- 'next_steps': [
- 'Review your comprehensive strategy',
- 'Customize specific components as needed',
- 'Share with your team for feedback',
- 'Begin implementation following the roadmap'
- ],
- 'ai_insights': 'Your strategy leverages advanced AI analysis of your business context, competitive landscape, and industry best practices to create a data-driven content approach.',
- 'personalization_note': 'This strategy is uniquely tailored to your business based on your onboarding data, ensuring relevance and effectiveness.'
+ # Step 8: Complete
+ completion_content = EducationalContentManager.get_step_content(8)
+ completion_content = EducationalContentManager.update_completion_summary(
+ completion_content,
+ {
+ "performance_predictions": performance_predictions,
+ "implementation_roadmap": implementation_roadmap,
+ "risk_assessment": risk_assessment
}
- })}\n\n"
+ )
+
+ # Save the comprehensive strategy to database
+ try:
+ from models.enhanced_strategy_models import EnhancedContentStrategy
+
+ # Create enhanced strategy record
+ enhanced_strategy = EnhancedContentStrategy(
+ user_id=user_id,
+ name=strategy_name or "Enhanced Content Strategy",
+ industry="technology", # Default, can be updated later
+
+ # Store the comprehensive AI analysis in the dedicated field
+ comprehensive_ai_analysis=comprehensive_strategy,
+
+ # Store metadata
+ ai_recommendations=comprehensive_strategy,
+
+ # Mark as AI-generated and comprehensive
+ created_at=datetime.utcnow(),
+ updated_at=datetime.utcnow()
+ )
+
+ # Add to database
+ db.add(enhanced_strategy)
+ db.commit()
+ db.refresh(enhanced_strategy)
+
+ logger.info(f"πΎ Strategy saved to database with ID: {enhanced_strategy.id}")
+
+ # Update the comprehensive strategy with the database ID
+ comprehensive_strategy["metadata"]["strategy_id"] = enhanced_strategy.id
+
+ except Exception as db_error:
+ logger.error(f"β Error saving strategy to database: {str(db_error)}")
+ # Continue without database save, strategy is still available in memory
+
+ generate_comprehensive_strategy_polling._task_status[task_id].update({
+ "step": 8,
+ "progress": 100,
+ "status": "completed",
+ "message": "Strategy generation completed successfully!",
+ "strategy": comprehensive_strategy,
+ "completed_at": datetime.utcnow().isoformat(),
+ "educational_content": completion_content
+ })
+
+ # Store in global latest strategies for persistent access
+ _latest_strategies[user_id] = {
+ "strategy": comprehensive_strategy,
+ "completed_at": datetime.utcnow().isoformat(),
+ "task_id": task_id
+ }
+
+ logger.info(f"β Background strategy generation completed for task: {task_id}")
+ logger.info(f"πΎ Strategy stored in global storage for user: {user_id}")
except Exception as e:
- logger.error(f"β Error in streaming strategy generation: {str(e)}")
- yield f"data: {json.dumps({'error': f'Strategy generation failed: {str(e)}', 'progress': 0, 'success': False})}\n\n"
+ logger.error(f"β Error in background strategy generation for task {task_id}: {str(e)}")
+ generate_comprehensive_strategy_polling._task_status[task_id].update({
+ "status": "failed",
+ "error": str(e),
+ "message": f"Strategy generation failed: {str(e)}",
+ "failed_at": datetime.utcnow().isoformat()
+ })
- return StreamingResponse(
- generate_strategy_stream(),
- media_type="text/plain",
- headers={
- "Cache-Control": "no-cache",
- "Connection": "keep-alive",
- "Access-Control-Allow-Origin": "*",
- "Access-Control-Allow-Headers": "Cache-Control"
- }
- )
+ # Start the background task
+ asyncio.create_task(generate_strategy_background())
- except Exception as e:
- logger.error(f"β Error starting streaming strategy generation: {str(e)}")
- raise HTTPException(
- status_code=500,
- detail=f"Failed to start streaming strategy generation: {str(e)}"
- )
-
-@router.get("/ai-generation-education")
-async def get_ai_generation_education() -> Dict[str, Any]:
- """Get educational content about the AI generation process."""
- try:
- logger.info("π Providing AI generation educational content")
-
- educational_content = {
- "title": "π€ AI-Powered Strategy Generation",
- "subtitle": "Understanding How We Create Your Content Strategy",
- "overview": {
- "description": "Our AI system analyzes your business data and generates a comprehensive content strategy using advanced machine learning and industry best practices.",
- "total_time": "2-3 minutes",
- "components": 6,
- "ai_model": "Google Gemini Pro",
- "personalization_level": "High"
- },
- "process_steps": [
- {
- "step": 1,
- "title": "π Data Analysis",
- "description": "Analyzing your onboarding data to understand your business context",
- "duration": "5-10 seconds",
- "details": [
- "Website analysis data processing",
- "Research preferences analysis",
- "API configuration review",
- "Historical performance assessment"
- ],
- "ai_prompt_example": "Analyze user onboarding data to extract business context, audience insights, and competitive positioning..."
- },
- {
- "step": 2,
- "title": "ποΈ Foundation Building",
- "description": "Creating the core strategy framework based on your objectives",
- "duration": "5-10 seconds",
- "details": [
- "Business objectives mapping",
- "Target metrics definition",
- "Budget allocation strategy",
- "Timeline planning"
- ],
- "ai_prompt_example": "Generate strategic foundation: business objectives, target metrics, budget allocation, and timeline planning..."
- },
- {
- "step": 3,
- "title": "π§ Strategic Intelligence",
- "description": "AI analyzes your market position and identifies opportunities",
- "duration": "15-20 seconds",
- "details": [
- "Market positioning analysis",
- "Opportunity identification",
- "Growth potential assessment",
- "Competitive advantage mapping"
- ],
- "ai_prompt_example": "Analyze market position, identify strategic opportunities, assess growth potential, and map competitive advantages..."
- },
- {
- "step": 4,
- "title": "π Competitive Intelligence",
- "description": "Analyzing competitors to identify gaps and opportunities",
- "duration": "20-25 seconds",
- "details": [
- "Competitor content strategies",
- "Market gap analysis",
- "Differentiation opportunities",
- "Industry trend analysis"
- ],
- "ai_prompt_example": "Analyze competitor content strategies, identify market gaps, find differentiation opportunities, and assess industry trends..."
- },
- {
- "step": 5,
- "title": "π Content Calendar Creation",
- "description": "Building a comprehensive content schedule optimized for your audience",
- "duration": "25-30 seconds",
- "details": [
- "Content piece generation",
- "Optimal publishing schedule",
- "Audience engagement timing",
- "Content repurposing strategy"
- ],
- "ai_prompt_example": "Generate content pieces, optimize publishing schedule, determine audience engagement timing, and plan content repurposing..."
- },
- {
- "step": 6,
- "title": "π Performance Forecasting",
- "description": "Predicting content performance and ROI based on industry data",
- "duration": "15-20 seconds",
- "details": [
- "Traffic growth projections",
- "ROI predictions",
- "Conversion rate estimates",
- "Engagement metrics forecasting"
- ],
- "ai_prompt_example": "Analyze industry benchmarks, predict traffic growth, estimate ROI, forecast conversion rates, and project engagement metrics..."
- },
- {
- "step": 7,
- "title": "πΊοΈ Implementation Roadmap",
- "description": "Creating a step-by-step plan to execute your strategy",
- "duration": "15-20 seconds",
- "details": [
- "Phase-by-phase breakdown",
- "Timeline with milestones",
- "Resource allocation",
- "Success checkpoints"
- ],
- "ai_prompt_example": "Create phase-by-phase breakdown, establish timeline with milestones, allocate resources, and set success checkpoints..."
- },
- {
- "step": 8,
- "title": "β οΈ Risk Assessment",
- "description": "Identifying potential challenges and creating mitigation strategies",
- "duration": "10-15 seconds",
- "details": [
- "Risk identification",
- "Risk probability analysis",
- "Mitigation strategies",
- "Contingency planning"
- ],
- "ai_prompt_example": "Identify potential risks, analyze risk probabilities, develop mitigation strategies, and create contingency plans..."
- }
- ],
- "ai_technology": {
- "model": "Google Gemini Pro",
- "capabilities": [
- "Advanced natural language processing",
- "Context-aware analysis",
- "Industry knowledge integration",
- "Personalized recommendations"
- ],
- "data_sources": [
- "Your onboarding data",
- "Industry benchmarks",
- "Best practices database",
- "Market research insights"
- ]
- },
- "personalization_features": {
- "data_points_used": [
- "Business objectives and goals",
- "Target audience demographics",
- "Industry and market context",
- "Competitive landscape",
- "Content preferences and style",
- "Budget and resource constraints"
- ],
- "customization_level": "High",
- "adaptation_factors": [
- "Industry-specific insights",
- "Audience behavior patterns",
- "Competitive positioning",
- "Resource availability"
- ]
- },
- "quality_assurance": {
- "validation_steps": [
- "Data completeness check",
- "Strategy coherence validation",
- "Industry alignment verification",
- "Implementation feasibility assessment"
- ],
- "fallback_mechanisms": [
- "Industry best practices",
- "Standard templates",
- "Benchmark data",
- "Expert recommendations"
- ]
- },
- "tips_for_users": [
- "π‘ The more detailed your onboarding data, the more personalized your strategy will be",
- "π Review and customize the generated strategy to match your specific needs",
- "π Use the strategy as a starting point and iterate based on performance",
- "π Monitor results and adjust the strategy as your business evolves",
- "π₯ Share the strategy with your team for feedback and buy-in"
- ],
- "technical_details": {
- "processing_time": "2-3 minutes total",
- "ai_calls": "8 specialized AI analyses",
- "data_processing": "Real-time onboarding data integration",
- "output_format": "Structured JSON with comprehensive strategy components",
- "scalability": "Handles multiple concurrent generations"
- }
- }
+ logger.info(f"β Polling-based AI strategy generation started for user: {user_id}, task: {task_id}")
return ResponseBuilder.create_success_response(
- message="AI generation educational content retrieved successfully",
- data=educational_content
+ message="AI strategy generation started successfully",
+ data={
+ "task_id": task_id,
+ "status": "started",
+ "message": "Strategy generation is running in the background. Use the task_id to check progress.",
+ "polling_endpoint": f"/api/content-planning/content-strategy/ai-generation/strategy-generation-status/{task_id}",
+ "estimated_completion": "2-3 minutes"
+ }
)
except Exception as e:
- logger.error(f"β Error getting AI generation education: {str(e)}")
- raise ContentPlanningErrorHandler.handle_general_error(e, "get_ai_generation_education")
\ No newline at end of file
+ logger.error(f"β Error starting polling-based strategy generation: {str(e)}")
+ raise ContentPlanningErrorHandler.handle_general_error(e, "generate_comprehensive_strategy_polling")
+
+@router.get("/strategy-generation-status/{task_id}")
+async def get_strategy_generation_status_by_task(
+ task_id: str,
+ db: Session = Depends(get_db)
+) -> Dict[str, Any]:
+ """Get the status of strategy generation for a specific task."""
+ try:
+ logger.info(f"Getting strategy generation status for task: {task_id}")
+
+ # Check if task status exists
+ if not hasattr(generate_comprehensive_strategy_polling, '_task_status'):
+ raise HTTPException(
+ status_code=404,
+ detail="No task status found. Task may have expired or never existed."
+ )
+
+ task_status = generate_comprehensive_strategy_polling._task_status.get(task_id)
+
+ if not task_status:
+ raise HTTPException(
+ status_code=404,
+ detail=f"Task {task_id} not found. It may have expired or never existed."
+ )
+
+ logger.info(f"β Strategy generation status retrieved for task: {task_id}")
+
+ return ResponseBuilder.create_success_response(
+ message="Strategy generation status retrieved successfully",
+ data=task_status
+ )
+
+ except HTTPException:
+ raise
+ except Exception as e:
+ logger.error(f"β Error getting strategy generation status: {str(e)}")
+ raise ContentPlanningErrorHandler.handle_general_error(e, "get_strategy_generation_status_by_task")
+
+@router.get("/latest-strategy")
+async def get_latest_generated_strategy(
+ user_id: int = Query(1, description="User ID"),
+ db: Session = Depends(get_db)
+) -> Dict[str, Any]:
+ """Get the latest generated strategy from the polling system or database."""
+ try:
+ logger.info(f"π Getting latest generated strategy for user: {user_id}")
+
+ # First, try to get from database (most reliable)
+ try:
+ from models.enhanced_strategy_models import EnhancedContentStrategy
+ from sqlalchemy import desc
+
+ # Query for the most recent strategy with comprehensive AI analysis
+ latest_db_strategy = db.query(EnhancedContentStrategy).filter(
+ EnhancedContentStrategy.user_id == user_id,
+ EnhancedContentStrategy.comprehensive_ai_analysis.isnot(None)
+ ).order_by(desc(EnhancedContentStrategy.created_at)).first()
+
+ if latest_db_strategy and latest_db_strategy.comprehensive_ai_analysis:
+ logger.info(f"β Found latest strategy in database: {latest_db_strategy.id}")
+ return ResponseBuilder.create_success_response(
+ message="Latest generated strategy retrieved successfully from database",
+ data={
+ "user_id": user_id,
+ "strategy": latest_db_strategy.comprehensive_ai_analysis,
+ "completed_at": latest_db_strategy.created_at.isoformat(),
+ "strategy_id": latest_db_strategy.id
+ }
+ )
+ except Exception as db_error:
+ logger.warning(f"β οΈ Database query failed: {str(db_error)}")
+
+ # Fallback: Check in-memory task status
+ if not hasattr(generate_comprehensive_strategy_polling, '_task_status'):
+ logger.warning("β οΈ No task status storage found")
+ return ResponseBuilder.create_not_found_response(
+ message="No strategy generation tasks found",
+ data={"user_id": user_id, "strategy": None}
+ )
+
+ # Debug: Log all task statuses
+ logger.info(f"π Total tasks in storage: {len(generate_comprehensive_strategy_polling._task_status)}")
+ for task_id, task_status in generate_comprehensive_strategy_polling._task_status.items():
+ logger.info(f" Task {task_id}: user_id={task_status.get('user_id')}, status={task_status.get('status')}, has_strategy={bool(task_status.get('strategy'))}")
+
+ # Find the most recent completed strategy for this user
+ latest_strategy = None
+ latest_completion_time = None
+
+ for task_id, task_status in generate_comprehensive_strategy_polling._task_status.items():
+ logger.info(f"π Checking task {task_id}: user_id={task_status.get('user_id')} vs requested {user_id}")
+
+ if (task_status.get("user_id") == user_id and
+ task_status.get("status") == "completed" and
+ task_status.get("strategy")):
+
+ completion_time = task_status.get("completed_at")
+ logger.info(f"β Found completed strategy for user {user_id} at {completion_time}")
+
+ if completion_time and (latest_completion_time is None or completion_time > latest_completion_time):
+ latest_strategy = task_status.get("strategy")
+ latest_completion_time = completion_time
+ logger.info(f"π Updated latest strategy with completion time: {completion_time}")
+
+ if latest_strategy:
+ logger.info(f"β Found latest generated strategy for user: {user_id}")
+ return ResponseBuilder.create_success_response(
+ message="Latest generated strategy retrieved successfully from memory",
+ data={
+ "user_id": user_id,
+ "strategy": latest_strategy,
+ "completed_at": latest_completion_time
+ }
+ )
+ else:
+ logger.info(f"β οΈ No completed strategies found for user: {user_id}")
+ return ResponseBuilder.create_not_found_response(
+ message="No completed strategy generation found",
+ data={"user_id": user_id, "strategy": None}
+ )
+
+ except Exception as e:
+ logger.error(f"β Error getting latest generated strategy: {str(e)}")
+ raise ContentPlanningErrorHandler.handle_general_error(e, "get_latest_generated_strategy")
diff --git a/backend/api/content_planning/api/content_strategy/endpoints/content_strategy/__init__.py b/backend/api/content_planning/api/content_strategy/endpoints/content_strategy/__init__.py
new file mode 100644
index 00000000..e6db6f56
--- /dev/null
+++ b/backend/api/content_planning/api/content_strategy/endpoints/content_strategy/__init__.py
@@ -0,0 +1,8 @@
+"""
+Content Strategy Educational Content Module
+Provides educational content and messages for strategy generation process.
+"""
+
+from .educational_content import EducationalContentManager
+
+__all__ = ['EducationalContentManager']
\ No newline at end of file
diff --git a/backend/api/content_planning/api/content_strategy/endpoints/content_strategy/educational_content.py b/backend/api/content_planning/api/content_strategy/endpoints/content_strategy/educational_content.py
new file mode 100644
index 00000000..74d7ca8a
--- /dev/null
+++ b/backend/api/content_planning/api/content_strategy/endpoints/content_strategy/educational_content.py
@@ -0,0 +1,319 @@
+"""
+Educational Content Manager
+Manages educational content and messages for strategy generation process.
+"""
+
+from typing import Dict, Any, List
+from datetime import datetime
+
+
+class EducationalContentManager:
+ """Manages educational content for strategy generation steps."""
+
+ @staticmethod
+ def get_initialization_content() -> Dict[str, Any]:
+ """Get educational content for initialization step."""
+ return {
+ "title": "π€ AI-Powered Strategy Generation",
+ "description": "Initializing AI analysis and preparing educational content...",
+ "details": [
+ "π§ Setting up AI services",
+ "π Loading user context",
+ "π― Preparing strategy framework",
+ "π Generating educational content"
+ ],
+ "insight": "We're getting everything ready for your personalized AI strategy generation.",
+ "estimated_time": "2-3 minutes total"
+ }
+
+ @staticmethod
+ def get_step_content(step: int) -> Dict[str, Any]:
+ """Get educational content for a specific step."""
+ step_content = {
+ 1: EducationalContentManager._get_user_context_content(),
+ 2: EducationalContentManager._get_foundation_content(),
+ 3: EducationalContentManager._get_strategic_insights_content(),
+ 4: EducationalContentManager._get_competitive_analysis_content(),
+ 5: EducationalContentManager._get_performance_predictions_content(),
+ 6: EducationalContentManager._get_implementation_roadmap_content(),
+ 7: EducationalContentManager._get_compilation_content(),
+ 8: EducationalContentManager._get_completion_content()
+ }
+
+ return step_content.get(step, EducationalContentManager._get_default_content())
+
+ @staticmethod
+ def get_step_completion_content(step: int, result_data: Dict[str, Any] = None) -> Dict[str, Any]:
+ """Get educational content for step completion."""
+ completion_content = {
+ 3: EducationalContentManager._get_strategic_insights_completion(result_data),
+ 4: EducationalContentManager._get_competitive_analysis_completion(result_data),
+ 5: EducationalContentManager._get_performance_predictions_completion(result_data),
+ 6: EducationalContentManager._get_implementation_roadmap_completion(result_data)
+ }
+
+ return completion_content.get(step, EducationalContentManager._get_default_completion())
+
+ @staticmethod
+ def _get_user_context_content() -> Dict[str, Any]:
+ """Get educational content for user context analysis."""
+ return {
+ "title": "π Analyzing Your Data",
+ "description": "We're gathering all your onboarding information to create a personalized strategy.",
+ "details": [
+ "π Website analysis data",
+ "π― Research preferences",
+ "π API configurations",
+ "π Historical performance metrics"
+ ],
+ "insight": "Your data helps us understand your business context, target audience, and competitive landscape.",
+ "ai_prompt_preview": "Analyzing user onboarding data to extract business context, audience insights, and competitive positioning..."
+ }
+
+ @staticmethod
+ def _get_foundation_content() -> Dict[str, Any]:
+ """Get educational content for foundation building."""
+ return {
+ "title": "ποΈ Building Foundation",
+ "description": "Creating the core strategy framework based on your business objectives.",
+ "details": [
+ "π― Business objectives mapping",
+ "π Target metrics definition",
+ "π° Budget allocation strategy",
+ "β° Timeline planning"
+ ],
+ "insight": "A solid foundation ensures your content strategy aligns with business goals and resources.",
+ "ai_prompt_preview": "Generating strategic foundation: business objectives, target metrics, budget allocation, and timeline planning..."
+ }
+
+ @staticmethod
+ def _get_strategic_insights_content() -> Dict[str, Any]:
+ """Get educational content for strategic insights generation."""
+ return {
+ "title": "π§ Strategic Intelligence Analysis",
+ "description": "AI is analyzing your market position and identifying strategic opportunities.",
+ "details": [
+ "π― Market positioning analysis",
+ "π‘ Opportunity identification",
+ "π Growth potential assessment",
+ "πͺ Competitive advantage mapping"
+ ],
+ "insight": "Strategic insights help you understand where you stand in the market and how to differentiate.",
+ "ai_prompt_preview": "Analyzing market position, identifying strategic opportunities, assessing growth potential, and mapping competitive advantages...",
+ "estimated_time": "15-20 seconds"
+ }
+
+ @staticmethod
+ def _get_competitive_analysis_content() -> Dict[str, Any]:
+ """Get educational content for competitive analysis."""
+ return {
+ "title": "π Competitive Intelligence Analysis",
+ "description": "AI is analyzing your competitors to identify gaps and opportunities.",
+ "details": [
+ "π’ Competitor content strategies",
+ "π Market gap analysis",
+ "π― Differentiation opportunities",
+ "π Industry trend analysis"
+ ],
+ "insight": "Understanding your competitors helps you find unique angles and underserved market segments.",
+ "ai_prompt_preview": "Analyzing competitor content strategies, identifying market gaps, finding differentiation opportunities, and assessing industry trends...",
+ "estimated_time": "20-25 seconds"
+ }
+
+ @staticmethod
+ def _get_performance_predictions_content() -> Dict[str, Any]:
+ """Get educational content for performance predictions."""
+ return {
+ "title": "π Performance Forecasting",
+ "description": "AI is predicting content performance and ROI based on industry data.",
+ "details": [
+ "π Traffic growth projections",
+ "π° ROI predictions",
+ "π― Conversion rate estimates",
+ "π Engagement metrics forecasting"
+ ],
+ "insight": "Performance predictions help you set realistic expectations and optimize resource allocation.",
+ "ai_prompt_preview": "Analyzing industry benchmarks, predicting traffic growth, estimating ROI, forecasting conversion rates, and projecting engagement metrics...",
+ "estimated_time": "15-20 seconds"
+ }
+
+ @staticmethod
+ def _get_implementation_roadmap_content() -> Dict[str, Any]:
+ """Get educational content for implementation roadmap."""
+ return {
+ "title": "πΊοΈ Implementation Roadmap",
+ "description": "AI is creating a detailed implementation plan for your content strategy.",
+ "details": [
+ "π Task breakdown and timeline",
+ "π₯ Resource allocation planning",
+ "π― Milestone definition",
+ "π Success metric tracking"
+ ],
+ "insight": "A clear implementation roadmap ensures successful strategy execution and measurable results.",
+ "ai_prompt_preview": "Creating implementation roadmap: task breakdown, resource allocation, milestone planning, and success metric definition...",
+ "estimated_time": "15-20 seconds"
+ }
+
+ @staticmethod
+ def _get_risk_assessment_content() -> Dict[str, Any]:
+ """Get educational content for risk assessment."""
+ return {
+ "title": "β οΈ Risk Assessment",
+ "description": "AI is identifying potential risks and mitigation strategies for your content strategy.",
+ "details": [
+ "π Risk identification and analysis",
+ "π Risk probability assessment",
+ "π‘οΈ Mitigation strategy development",
+ "π Risk monitoring framework"
+ ],
+ "insight": "Proactive risk assessment helps you prepare for challenges and maintain strategy effectiveness.",
+ "ai_prompt_preview": "Assessing risks: identifying potential challenges, analyzing probability and impact, developing mitigation strategies, and creating monitoring framework...",
+ "estimated_time": "10-15 seconds"
+ }
+
+ @staticmethod
+ def _get_compilation_content() -> Dict[str, Any]:
+ """Get educational content for strategy compilation."""
+ return {
+ "title": "π Strategy Compilation",
+ "description": "AI is compiling all components into a comprehensive content strategy.",
+ "details": [
+ "π Component integration",
+ "π Data synthesis",
+ "π Strategy documentation",
+ "β Quality validation"
+ ],
+ "insight": "A comprehensive strategy integrates all components into a cohesive, actionable plan.",
+ "ai_prompt_preview": "Compiling comprehensive strategy: integrating all components, synthesizing data, documenting strategy, and validating quality...",
+ "estimated_time": "5-10 seconds"
+ }
+
+ @staticmethod
+ def _get_completion_content() -> Dict[str, Any]:
+ """Get educational content for strategy completion."""
+ return {
+ "title": "π Strategy Generation Complete!",
+ "description": "Your comprehensive AI-powered content strategy is ready for review!",
+ "summary": {
+ "total_components": 5,
+ "successful_components": 5,
+ "estimated_roi": "15-25%",
+ "implementation_timeline": "12 months",
+ "risk_level": "Medium"
+ },
+ "key_achievements": [
+ "π§ Strategic insights generated",
+ "π Competitive analysis completed",
+ "π Performance predictions calculated",
+ "πΊοΈ Implementation roadmap planned",
+ "β οΈ Risk assessment conducted"
+ ],
+ "next_steps": [
+ "Review your comprehensive strategy in the Strategic Intelligence tab",
+ "Customize specific components as needed",
+ "Confirm the strategy to proceed",
+ "Generate content calendar based on confirmed strategy"
+ ],
+ "ai_insights": "Your strategy leverages advanced AI analysis of your business context, competitive landscape, and industry best practices to create a data-driven content approach.",
+ "personalization_note": "This strategy is uniquely tailored to your business based on your onboarding data, ensuring relevance and effectiveness.",
+ "content_calendar_note": "Content calendar will be generated separately after you review and confirm this strategy, ensuring it's based on your final approved strategy."
+ }
+
+ @staticmethod
+ def _get_default_content() -> Dict[str, Any]:
+ """Get default educational content."""
+ return {
+ "title": "π Processing",
+ "description": "AI is working on your strategy...",
+ "details": [
+ "β³ Processing in progress",
+ "π Analyzing data",
+ "π― Generating insights",
+ "π Compiling results"
+ ],
+ "insight": "The AI is working hard to create your personalized strategy.",
+ "estimated_time": "A few moments"
+ }
+
+ @staticmethod
+ def _get_strategic_insights_completion(result_data: Dict[str, Any] = None) -> Dict[str, Any]:
+ """Get completion content for strategic insights."""
+ insights_count = len(result_data.get("insights", [])) if result_data else 0
+ return {
+ "title": "β Strategic Insights Complete",
+ "description": "Successfully identified key strategic opportunities and market positioning.",
+ "achievement": f"Generated {insights_count} strategic insights",
+ "next_step": "Moving to competitive analysis..."
+ }
+
+ @staticmethod
+ def _get_competitive_analysis_completion(result_data: Dict[str, Any] = None) -> Dict[str, Any]:
+ """Get completion content for competitive analysis."""
+ competitors_count = len(result_data.get("competitors", [])) if result_data else 0
+ return {
+ "title": "β Competitive Analysis Complete",
+ "description": "Successfully analyzed competitive landscape and identified market opportunities.",
+ "achievement": f"Analyzed {competitors_count} competitors",
+ "next_step": "Moving to performance predictions..."
+ }
+
+ @staticmethod
+ def _get_performance_predictions_completion(result_data: Dict[str, Any] = None) -> Dict[str, Any]:
+ """Get completion content for performance predictions."""
+ estimated_roi = result_data.get("estimated_roi", "15-25%") if result_data else "15-25%"
+ return {
+ "title": "β Performance Predictions Complete",
+ "description": "Successfully predicted content performance and ROI.",
+ "achievement": f"Predicted {estimated_roi} ROI",
+ "next_step": "Moving to implementation roadmap..."
+ }
+
+ @staticmethod
+ def _get_implementation_roadmap_completion(result_data: Dict[str, Any] = None) -> Dict[str, Any]:
+ """Get completion content for implementation roadmap."""
+ timeline = result_data.get("total_duration", "12 months") if result_data else "12 months"
+ return {
+ "title": "β Implementation Roadmap Complete",
+ "description": "Successfully created detailed implementation plan.",
+ "achievement": f"Planned {timeline} implementation timeline",
+ "next_step": "Moving to compilation..."
+ }
+
+ @staticmethod
+ def _get_risk_assessment_completion(result_data: Dict[str, Any] = None) -> Dict[str, Any]:
+ """Get completion content for risk assessment."""
+ risk_level = result_data.get("overall_risk_level", "Medium") if result_data else "Medium"
+ return {
+ "title": "β Risk Assessment Complete",
+ "description": "Successfully identified risks and mitigation strategies.",
+ "achievement": f"Assessed {risk_level} risk level",
+ "next_step": "Finalizing comprehensive strategy..."
+ }
+
+ @staticmethod
+ def _get_default_completion() -> Dict[str, Any]:
+ """Get default completion content."""
+ return {
+ "title": "β Step Complete",
+ "description": "Successfully completed this step.",
+ "achievement": "Step completed successfully",
+ "next_step": "Moving to next step..."
+ }
+
+ @staticmethod
+ def update_completion_summary(completion_content: Dict[str, Any], strategy_data: Dict[str, Any]) -> Dict[str, Any]:
+ """Update completion content with actual strategy data."""
+ if "summary" in completion_content:
+ content_calendar = strategy_data.get("content_calendar", {})
+ performance_predictions = strategy_data.get("performance_predictions", {})
+ implementation_roadmap = strategy_data.get("implementation_roadmap", {})
+ risk_assessment = strategy_data.get("risk_assessment", {})
+
+ completion_content["summary"].update({
+ "total_content_pieces": len(content_calendar.get("content_pieces", [])),
+ "estimated_roi": performance_predictions.get("estimated_roi", "15-25%"),
+ "implementation_timeline": implementation_roadmap.get("total_duration", "12 months"),
+ "risk_level": risk_assessment.get("overall_risk_level", "Medium")
+ })
+
+ return completion_content
\ No newline at end of file
diff --git a/backend/api/content_planning/api/enhanced_strategy_routes.py b/backend/api/content_planning/api/enhanced_strategy_routes.py
index 6b4b551e..4e9fe4b9 100644
--- a/backend/api/content_planning/api/enhanced_strategy_routes.py
+++ b/backend/api/content_planning/api/enhanced_strategy_routes.py
@@ -1122,4 +1122,4 @@ async def refresh_autofill(
)
except Exception as e:
logger.error(f"β Error generating fresh auto-fill payload: {str(e)}")
- raise ContentPlanningErrorHandler.handle_general_error(e, "refresh_autofill")
\ No newline at end of file
+ raise ContentPlanningErrorHandler.handle_general_error(e, "refresh_autofill")
\ No newline at end of file
diff --git a/backend/api/content_planning/services/content_strategy/ai_generation/strategy_generator.py b/backend/api/content_planning/services/content_strategy/ai_generation/strategy_generator.py
index c86cea7f..87252bf9 100644
--- a/backend/api/content_planning/services/content_strategy/ai_generation/strategy_generator.py
+++ b/backend/api/content_planning/services/content_strategy/ai_generation/strategy_generator.py
@@ -60,7 +60,7 @@ class AIStrategyGenerator:
strategy_name: Optional custom strategy name
Returns:
- Comprehensive strategy with all components
+ Comprehensive strategy with all components (EXCLUDING content calendar)
Raises:
RuntimeError: If any AI component fails to generate
@@ -77,19 +77,16 @@ class AIStrategyGenerator:
# Step 3: Generate competitive analysis
competitive_analysis = await self._generate_competitive_analysis(base_strategy, context)
- # Step 4: Generate content calendar
- content_calendar = await self._generate_content_calendar(base_strategy, context)
-
- # Step 5: Generate performance predictions
+ # Step 4: Generate performance predictions
performance_predictions = await self._generate_performance_predictions(base_strategy, context)
- # Step 6: Generate implementation roadmap
+ # Step 5: Generate implementation roadmap
implementation_roadmap = await self._generate_implementation_roadmap(base_strategy, context)
- # Step 7: Generate risk assessment
+ # Step 6: Generate risk assessment
risk_assessment = await self._generate_risk_assessment(base_strategy, context)
- # Step 8: Compile comprehensive strategy
+ # Step 7: Compile comprehensive strategy (NO CONTENT CALENDAR)
comprehensive_strategy = {
"strategy_metadata": {
"generated_at": datetime.utcnow().isoformat(),
@@ -99,21 +96,21 @@ class AIStrategyGenerator:
"ai_model": "gemini-pro",
"personalization_level": "high",
"ai_generated": True,
- "comprehensive": True
+ "comprehensive": True,
+ "content_calendar_ready": False # Indicates calendar needs to be generated separately
},
"base_strategy": base_strategy,
"strategic_insights": strategic_insights,
"competitive_analysis": competitive_analysis,
- "content_calendar": content_calendar,
"performance_predictions": performance_predictions,
"implementation_roadmap": implementation_roadmap,
"risk_assessment": risk_assessment,
"summary": {
- "total_content_pieces": len(content_calendar.get("content_pieces", [])),
"estimated_roi": performance_predictions.get("estimated_roi", "15-25%"),
"implementation_timeline": implementation_roadmap.get("total_duration", "12 months"),
"risk_level": risk_assessment.get("overall_risk_level", "Medium"),
- "success_probability": performance_predictions.get("success_probability", "85%")
+ "success_probability": performance_predictions.get("success_probability", "85%"),
+ "next_step": "Review strategy and generate content calendar"
}
}
@@ -334,8 +331,55 @@ class AIStrategyGenerator:
}
},
"themes": {"type": "array", "items": {"type": "string"}},
- "schedule": {"type": "object"},
- "distribution_strategy": {"type": "object"}
+ "schedule": {
+ "type": "object",
+ "properties": {
+ "publishing_frequency": {"type": "string"},
+ "optimal_times": {"type": "array", "items": {"type": "string"}},
+ "content_mix": {
+ "type": "object",
+ "properties": {
+ "blog_posts": {"type": "string"},
+ "social_media": {"type": "string"},
+ "videos": {"type": "string"},
+ "infographics": {"type": "string"},
+ "newsletters": {"type": "string"}
+ }
+ },
+ "seasonal_adjustments": {
+ "type": "object",
+ "properties": {
+ "holiday_content": {"type": "array", "items": {"type": "string"}},
+ "seasonal_themes": {"type": "array", "items": {"type": "string"}},
+ "peak_periods": {"type": "array", "items": {"type": "string"}}
+ }
+ }
+ }
+ },
+ "distribution_strategy": {
+ "type": "object",
+ "properties": {
+ "primary_platforms": {"type": "array", "items": {"type": "string"}},
+ "cross_posting_strategy": {"type": "string"},
+ "platform_specific_content": {
+ "type": "object",
+ "properties": {
+ "linkedin_content": {"type": "array", "items": {"type": "string"}},
+ "twitter_content": {"type": "array", "items": {"type": "string"}},
+ "instagram_content": {"type": "array", "items": {"type": "string"}},
+ "facebook_content": {"type": "array", "items": {"type": "string"}}
+ }
+ },
+ "engagement_timing": {
+ "type": "object",
+ "properties": {
+ "best_times": {"type": "array", "items": {"type": "string"}},
+ "frequency": {"type": "string"},
+ "timezone_considerations": {"type": "string"}
+ }
+ }
+ }
+ }
}
}
@@ -483,8 +527,33 @@ class AIStrategyGenerator:
}
}
},
- "timeline": {"type": "object"},
- "resource_allocation": {"type": "object"},
+ "timeline": {
+ "type": "object",
+ "properties": {
+ "start_date": {"type": "string"},
+ "end_date": {"type": "string"},
+ "key_milestones": {"type": "array", "items": {"type": "string"}},
+ "critical_path": {"type": "array", "items": {"type": "string"}}
+ }
+ },
+ "resource_allocation": {
+ "type": "object",
+ "properties": {
+ "team_requirements": {"type": "array", "items": {"type": "string"}},
+ "budget_allocation": {
+ "type": "object",
+ "properties": {
+ "total_budget": {"type": "string"},
+ "content_creation": {"type": "string"},
+ "technology_tools": {"type": "string"},
+ "marketing_promotion": {"type": "string"},
+ "external_resources": {"type": "string"}
+ }
+ },
+ "technology_needs": {"type": "array", "items": {"type": "string"}},
+ "external_resources": {"type": "array", "items": {"type": "string"}}
+ }
+ },
"success_metrics": {"type": "array", "items": {"type": "string"}},
"total_duration": {"type": "string"}
}
@@ -552,9 +621,25 @@ class AIStrategyGenerator:
}
},
"overall_risk_level": {"type": "string"},
- "risk_categories": {"type": "object"},
+ "risk_categories": {
+ "type": "object",
+ "properties": {
+ "technical_risks": {"type": "array", "items": {"type": "string"}},
+ "market_risks": {"type": "array", "items": {"type": "string"}},
+ "operational_risks": {"type": "array", "items": {"type": "string"}},
+ "financial_risks": {"type": "array", "items": {"type": "string"}}
+ }
+ },
"mitigation_strategies": {"type": "array", "items": {"type": "string"}},
- "monitoring_framework": {"type": "object"}
+ "monitoring_framework": {
+ "type": "object",
+ "properties": {
+ "key_indicators": {"type": "array", "items": {"type": "string"}},
+ "monitoring_frequency": {"type": "string"},
+ "escalation_procedures": {"type": "array", "items": {"type": "string"}},
+ "review_schedule": {"type": "string"}
+ }
+ }
}
}
diff --git a/backend/api/content_planning/services/content_strategy/core/strategy_service.py b/backend/api/content_planning/services/content_strategy/core/strategy_service.py
index d00be47c..b7ce570e 100644
--- a/backend/api/content_planning/services/content_strategy/core/strategy_service.py
+++ b/backend/api/content_planning/services/content_strategy/core/strategy_service.py
@@ -506,7 +506,7 @@ class EnhancedStrategyService:
def _merge_strategy_with_onboarding(self, strategy_data: Dict[str, Any], field_transformations: Dict[str, Any]) -> Dict[str, Any]:
"""Merge strategy data with onboarding data."""
- merged_data = strategy_data.copy()
+ merged_data = strategy_data.copy()
for field, transformation in field_transformations.items():
if field not in merged_data or merged_data[field] is None:
diff --git a/docs/sse_migration_strategy.md b/docs/sse_migration_strategy.md
new file mode 100644
index 00000000..be44cd84
--- /dev/null
+++ b/docs/sse_migration_strategy.md
@@ -0,0 +1,343 @@
+# SSE Migration Strategy & Implementation Plan
+
+## π¨ **Current Implementation Problems**
+
+### **Backend Issues**
+- **Complex SSE Manager**: The `SSEAIServiceManager` with lambda functions is overly complex
+- **Async Generator Problems**: The `sse_yield` function using `__anext__()` is fragile
+- **Message Format Inconsistency**: Backend sends different message formats that frontend struggles to parse
+- **Tight Coupling**: AI service manager is tightly coupled to SSE implementation
+- **Error Propagation**: Errors in one component cascade to others
+- **Debugging Difficulty**: Complex async flows make debugging hard
+
+### **Frontend Issues**
+- **EventSource Limitations**: No built-in reconnection, poor error handling
+- **Message Parsing Complexity**: Too many message types to handle
+- **Timeout Handling**: Frontend timeouts don't align with backend processing
+- **Connection State Management**: Poor handling of connection states
+- **Progress Tracking**: Inconsistent progress calculation and display
+
+### **Architecture Problems**
+- **Tight Coupling**: Frontend and backend are tightly coupled to specific message formats
+- **No Reusability**: SSE implementation is specific to strategy generation
+- **Error Handling**: Inconsistent error handling across components
+- **Testing Difficulty**: Complex async flows make testing challenging
+
+## π― **Proposed Solution: Clean SSE with sse-starlette**
+
+### **Phase 1: MVP Polling Solution (1-2 hours)**
+**Goal**: Get strategy generation working immediately with simple polling
+
+**Implementation**:
+- Replace complex SSE with simple polling mechanism
+- Poll strategy status every 10 seconds
+- Show progress modal with educational content
+- Handle timeouts gracefully
+- Remove all SSE-related complexity
+
+**Benefits**:
+- β Immediate working solution
+- β Simple to implement and debug
+- β Reliable and predictable
+- β Easy to test
+
+### **Phase 2: Proper SSE Implementation (1-2 days)**
+**Goal**: Implement clean, reusable SSE infrastructure
+
+**Implementation**:
+- Use `sse-starlette` for backend SSE
+- Create reusable SSE client for frontend
+- Standardize message format
+- Add proper error handling and reconnection
+- Make SSE infrastructure reusable for other features
+
+**Benefits**:
+- β Real-time updates
+- β Better user experience
+- β Reusable infrastructure
+- β Proper error handling
+
+## ποΈ **Technical Architecture**
+
+### **Backend: sse-starlette Implementation**
+
+#### **Core SSE Module** (`backend/services/sse/`)
+```
+backend/services/sse/
+βββ __init__.py
+βββ sse_manager.py # Core SSE management
+βββ message_formatter.py # Standardized message formatting
+βββ connection_manager.py # Connection lifecycle management
+βββ error_handler.py # SSE error handling
+βββ types.py # SSE message types and schemas
+```
+
+#### **SSE Manager Features**
+- **Connection Management**: Handle multiple SSE connections
+- **Message Broadcasting**: Send messages to specific clients
+- **Error Handling**: Graceful error handling and recovery
+- **Message Formatting**: Consistent message format across all features
+- **Connection Monitoring**: Track connection health and status
+
+#### **Message Format Standardization**
+```python
+# Standard SSE message format
+{
+ "event": "progress|complete|error|educational",
+ "data": {
+ "step": 1,
+ "progress": 10,
+ "message": "Processing...",
+ "educational_content": {...},
+ "timestamp": "2024-01-01T00:00:00Z"
+ }
+}
+```
+
+### **Frontend: Reusable SSE Client**
+
+#### **Core SSE Module** (`frontend/src/services/sse/`)
+```
+frontend/src/services/sse/
+βββ index.ts
+βββ SSEConnection.ts # Core SSE connection management
+βββ SSEEventManager.ts # Event handling and message parsing
+βββ SSEReconnection.ts # Automatic reconnection logic
+βββ SSEMessageTypes.ts # TypeScript types for messages
+βββ SSEUtils.ts # Utility functions
+```
+
+#### **SSE Client Features**
+- **Automatic Reconnection**: Handle connection drops gracefully
+- **Message Parsing**: Parse standardized message format
+- **Event Handling**: Handle different event types
+- **Error Recovery**: Recover from errors automatically
+- **Connection Monitoring**: Monitor connection health
+
+#### **React Hook** (`frontend/src/hooks/useSSE.ts`)
+```typescript
+const useSSE = (url: string, options?: SSEOptions) => {
+ // Returns: { data, error, isConnected, reconnect }
+}
+```
+
+## π **Implementation Phases**
+
+### **Phase 1: MVP Polling (Immediate - 1-2 hours)**
+
+#### **Backend Changes**
+1. **Remove SSE complexity** from `ai_generation_endpoints.py`
+2. **Simplify AI generation** to return immediately after starting
+3. **Add status endpoint** to check generation progress
+4. **Remove SSEAIServiceManager** and related complexity
+
+#### **Frontend Changes**
+1. **Replace SSE with polling** in `ContentStrategyBuilder.tsx`
+2. **Implement simple progress modal** with educational content
+3. **Add polling mechanism** (every 10 seconds)
+4. **Handle timeouts gracefully** (5-minute timeout)
+5. **Remove all SSE-related code**
+
+#### **Files to Modify**
+- `backend/api/content_planning/api/content_strategy/endpoints/ai_generation_endpoints.py`
+- `frontend/src/components/ContentPlanningDashboard/components/ContentStrategyBuilder.tsx`
+- `frontend/src/services/contentPlanningApi.ts`
+
+### **Phase 2: Clean SSE Infrastructure (1-2 days)**
+
+#### **Backend Implementation**
+1. **Create SSE infrastructure** (`backend/services/sse/`)
+2. **Implement sse-starlette endpoints** for strategy generation
+3. **Standardize message format** across all SSE endpoints
+4. **Add connection management** and error handling
+5. **Create reusable SSE utilities**
+
+#### **Frontend Implementation**
+1. **Create SSE client infrastructure** (`frontend/src/services/sse/`)
+2. **Implement React hook** for SSE connections
+3. **Add automatic reconnection** logic
+4. **Standardize message parsing** and event handling
+5. **Create reusable SSE components**
+
+#### **New Files to Create**
+```
+Backend:
+- backend/services/sse/__init__.py
+- backend/services/sse/sse_manager.py
+- backend/services/sse/message_formatter.py
+- backend/services/sse/connection_manager.py
+- backend/services/sse/error_handler.py
+- backend/services/sse/types.py
+
+Frontend:
+- frontend/src/services/sse/index.ts
+- frontend/src/services/sse/SSEConnection.ts
+- frontend/src/services/sse/SSEEventManager.ts
+- frontend/src/services/sse/SSEReconnection.ts
+- frontend/src/services/sse/SSEMessageTypes.ts
+- frontend/src/services/sse/SSEUtils.ts
+- frontend/src/hooks/useSSE.ts
+```
+
+### **Phase 3: Migration & Testing (1 day)**
+
+#### **Migration Steps**
+1. **Migrate strategy generation** to new SSE infrastructure
+2. **Test end-to-end functionality** with new SSE
+3. **Add comprehensive error handling** and recovery
+4. **Implement educational content** streaming
+5. **Add monitoring and logging** for SSE connections
+
+#### **Testing Strategy**
+1. **Unit tests** for SSE infrastructure
+2. **Integration tests** for SSE endpoints
+3. **End-to-end tests** for strategy generation
+4. **Error scenario testing** (network drops, timeouts)
+5. **Performance testing** (multiple concurrent connections)
+
+## π§ **Technical Specifications**
+
+### **Backend SSE Manager Interface**
+```python
+class SSEManager:
+ async def create_connection(self, client_id: str) -> SSEConnection
+ async def send_message(self, client_id: str, message: SSEMessage)
+ async def broadcast_message(self, message: SSEMessage, filter_func=None)
+ async def close_connection(self, client_id: str)
+ async def get_connection_status(self, client_id: str) -> ConnectionStatus
+```
+
+### **Frontend SSE Client Interface**
+```typescript
+interface SSEConnection {
+ connect(): Promise
+ disconnect(): void
+ send(message: SSEMessage): void
+ on(event: string, handler: EventHandler): void
+ off(event: string, handler: EventHandler): void
+ isConnected(): boolean
+ reconnect(): Promise
+}
+```
+
+### **Message Format Specification**
+```typescript
+interface SSEMessage {
+ event: 'progress' | 'complete' | 'error' | 'educational' | 'status'
+ data: {
+ step?: number
+ progress?: number
+ message?: string
+ educational_content?: EducationalContent
+ error?: string
+ timestamp: string
+ [key: string]: any
+ }
+}
+```
+
+## π― **Success Criteria**
+
+### **Phase 1 Success Criteria**
+- β Strategy generation works reliably
+- β No more "Request timed out" errors
+- β Users can see progress and educational content
+- β Simple, debuggable implementation
+- β Strategy creation completes successfully
+
+### **Phase 2 Success Criteria**
+- β Real-time progress updates via SSE
+- β Automatic reconnection on network issues
+- β Standardized message format across features
+- β Reusable SSE infrastructure
+- β Proper error handling and recovery
+- β Educational content streaming
+
+### **Phase 3 Success Criteria**
+- β All features migrated to new SSE infrastructure
+- β Comprehensive testing coverage
+- β Performance meets requirements
+- β Error scenarios handled gracefully
+- β Monitoring and logging in place
+
+## π **Migration Benefits**
+
+### **Immediate Benefits (Phase 1)**
+- **Reliability**: No more timeout errors
+- **Simplicity**: Easy to debug and maintain
+- **User Experience**: Clear progress feedback
+- **Stability**: Predictable behavior
+
+### **Long-term Benefits (Phase 2+)**
+- **Reusability**: SSE infrastructure for other features
+- **Real-time Updates**: Better user experience
+- **Scalability**: Handle multiple concurrent connections
+- **Maintainability**: Clean, modular architecture
+- **Extensibility**: Easy to add new SSE features
+
+## π **Implementation Notes**
+
+### **Dependencies**
+- **Backend**: `sse-starlette` package
+- **Frontend**: No additional dependencies (uses native EventSource)
+
+### **Configuration**
+- **SSE Timeout**: 5 minutes for long-running operations
+- **Reconnection**: Exponential backoff (1s, 2s, 4s, 8s, max 30s)
+- **Message Format**: JSON with standardized structure
+- **Error Handling**: Graceful degradation with fallback options
+
+### **Monitoring & Logging**
+- **Connection Status**: Track active connections
+- **Message Flow**: Log message types and frequencies
+- **Error Tracking**: Monitor and alert on SSE errors
+- **Performance Metrics**: Track response times and throughput
+
+### **Security Considerations**
+- **Authentication**: Validate client connections
+- **Rate Limiting**: Prevent abuse of SSE endpoints
+- **Message Validation**: Validate all incoming messages
+- **Connection Limits**: Limit concurrent connections per user
+
+## π **Rollback Plan**
+
+### **If Phase 1 Fails**
+- Revert to current SSE implementation
+- Keep polling as fallback option
+- Document issues for future reference
+
+### **If Phase 2 Fails**
+- Keep Phase 1 polling implementation
+- Identify specific issues with sse-starlette
+- Consider alternative SSE libraries or WebSocket implementation
+
+### **If Phase 3 Fails**
+- Rollback to Phase 2 implementation
+- Fix specific issues identified during testing
+- Re-run migration with fixes
+
+## π **References & Resources**
+
+### **Documentation**
+- [sse-starlette Documentation](https://github.com/sysid/sse-starlette)
+- [Server-Sent Events MDN](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events)
+- [EventSource API](https://developer.mozilla.org/en-US/docs/Web/API/EventSource)
+
+### **Best Practices**
+- [SSE Best Practices](https://html.spec.whatwg.org/multipage/server-sent-events.html)
+- [Real-time Web Applications](https://web.dev/real-time-web-applications/)
+- [Error Handling in SSE](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Error_handling)
+
+### **Examples & Templates**
+- [sse-starlette Examples](https://github.com/sysid/sse-starlette/tree/main/examples)
+- [React SSE Hook Examples](https://github.com/facebook/react/tree/main/packages/react-dom/src/events)
+- [FastAPI SSE Examples](https://fastapi.tiangolo.com/advanced/websockets/)
+
+---
+
+**Next Steps**:
+1. Commit current code
+2. Refresh session
+3. Start Phase 1 implementation (MVP polling)
+4. Test strategy generation works
+5. Proceed to Phase 2 (clean SSE infrastructure)
\ No newline at end of file
diff --git a/frontend/build/asset-manifest.json b/frontend/build/asset-manifest.json
index a9ce6251..fe4f6442 100644
--- a/frontend/build/asset-manifest.json
+++ b/frontend/build/asset-manifest.json
@@ -1,13 +1,13 @@
{
"files": {
"main.css": "/static/css/main.c9966057.css",
- "main.js": "/static/js/main.2ee5cd94.js",
+ "main.js": "/static/js/main.2819e23e.js",
"index.html": "/index.html",
"main.c9966057.css.map": "/static/css/main.c9966057.css.map",
- "main.2ee5cd94.js.map": "/static/js/main.2ee5cd94.js.map"
+ "main.2819e23e.js.map": "/static/js/main.2819e23e.js.map"
},
"entrypoints": [
"static/css/main.c9966057.css",
- "static/js/main.2ee5cd94.js"
+ "static/js/main.2819e23e.js"
]
}
\ No newline at end of file
diff --git a/frontend/build/index.html b/frontend/build/index.html
index 12534f39..677fc85e 100644
--- a/frontend/build/index.html
+++ b/frontend/build/index.html
@@ -1 +1 @@
-Alwrity - AI Content Creation Platform
\ No newline at end of file
+Alwrity - AI Content Creation Platform
\ No newline at end of file
diff --git a/frontend/src/components/ContentPlanningDashboard/components/ContentStrategyBuilder.tsx b/frontend/src/components/ContentPlanningDashboard/components/ContentStrategyBuilder.tsx
index 465e7455..ca82eccc 100644
--- a/frontend/src/components/ContentPlanningDashboard/components/ContentStrategyBuilder.tsx
+++ b/frontend/src/components/ContentPlanningDashboard/components/ContentStrategyBuilder.tsx
@@ -50,7 +50,8 @@ import {
Lightbulb as LightbulbIcon,
Psychology as PsychologyIcon,
Timeline as TimelineIcon,
- FiberManualRecord as FiberManualRecordIcon
+ FiberManualRecord as FiberManualRecordIcon,
+ Schedule as ScheduleIcon
} from '@mui/icons-material';
import { motion, AnimatePresence } from 'framer-motion';
import { useEnhancedStrategyStore, STRATEGIC_INPUT_FIELDS } from '../../../stores/enhancedStrategyStore';
@@ -63,6 +64,7 @@ import DataSourceTransparency from './DataSourceTransparency';
import { useCategoryReview } from './ContentStrategyBuilder/hooks/useCategoryReview';
import { useProgressTracking } from './ContentStrategyBuilder/hooks/useProgressTracking';
import { useAutoPopulation } from './ContentStrategyBuilder/hooks/useAutoPopulation';
+import { useActionButtonsBusinessLogic } from './ContentStrategyBuilder/components/ActionButtons';
// Import extracted utilities
import { getCategoryIcon, getCategoryColor, getCategoryName, getCategoryStatus } from './ContentStrategyBuilder/utils/categoryHelpers';
@@ -72,7 +74,12 @@ import { getEducationalContent } from './ContentStrategyBuilder/utils/educationa
import CategoryList from './ContentStrategyBuilder/components/CategoryList';
import ProgressTracker from './ContentStrategyBuilder/components/ProgressTracker';
import HeaderSection from './ContentStrategyBuilder/components/HeaderSection';
+import EducationalModal from './ContentStrategyBuilder/components/EducationalModal';
+import ActionButtons from './ContentStrategyBuilder/components/ActionButtons';
+import StrategyDisplay from './ContentStrategyBuilder/components/StrategyDisplay';
+import ErrorAlert from './ContentStrategyBuilder/components/ErrorAlert';
import { contentPlanningApi } from '../../../services/contentPlanningApi';
+import CategoryDetailView from './ContentStrategyBuilder/components/CategoryDetailView';
const ContentStrategyBuilder: React.FC = () => {
const {
@@ -155,6 +162,25 @@ const ContentStrategyBuilder: React.FC = () => {
completionStats
});
+ // Use ActionButtons business logic hook
+ const { handleCreateStrategy, handleSaveStrategy } = useActionButtonsBusinessLogic({
+ formData,
+ error,
+ currentStrategy,
+ setAIGenerating,
+ setError,
+ setCurrentStrategy,
+ setSaving,
+ setGenerationProgress,
+ setEducationalContent,
+ setShowEducationalModal,
+ validateAllFields,
+ getCompletionStats,
+ generateAIRecommendations,
+ createEnhancedStrategy,
+ contentPlanningApi
+ });
+
// Auto-populate from onboarding on first load
useEffect(() => {
if (!autoPopulateAttempted) {
@@ -211,294 +237,6 @@ const ContentStrategyBuilder: React.FC = () => {
};
}, []);
- const handleCreateStrategy = async () => {
- try {
- setAIGenerating(true);
- setError(null);
-
- console.log('Starting strategy creation...');
- console.log('Current formData:', formData);
- console.log('FormData ID:', formData.id);
-
- // If we have a saved strategy, use its ID
- if (formData.id) {
- console.log('Using existing strategy ID:', formData.id);
- await generateAIRecommendations(formData.id);
- } else {
- console.log('No strategy ID found, creating new strategy...');
- // If no strategy is saved yet, save it first, then generate AI insights
- const isValid = validateAllFields();
- console.log('Form validation result:', isValid);
-
- if (isValid) {
- const completionStats = getCompletionStats();
- const strategyData = {
- ...formData,
- completion_percentage: completionStats.completion_percentage,
- user_id: 1, // This would come from auth context
- name: formData.name || 'Enhanced Content Strategy',
- industry: formData.industry || 'General'
- };
-
- console.log('Attempting to create strategy with data:', strategyData);
-
- // Use SSE streaming endpoint for strategy generation with educational content
- await generateStrategyWithSSE(strategyData);
- } else {
- setError('Please fill in all required fields before generating AI insights.');
- console.error('Form validation failed. Cannot generate AI insights.');
- }
- }
- } catch (err: any) {
- setError(`Error generating AI recommendations: ${err.message || 'Unknown error'}`);
- console.error('Error in handleCreateStrategy:', err);
- } finally {
- setAIGenerating(false);
- }
- };
-
- const generateStrategyWithSSE = async (strategyData: any) => {
- try {
- console.log('π Starting SSE strategy generation...');
-
- // Initialize progress and educational content
- setGenerationProgress(0);
- setEducationalContent({
- title: 'π€ AI-Powered Strategy Generation',
- description: 'Initializing AI analysis and preparing educational content...',
- details: [
- 'π§ Setting up AI services',
- 'π Loading user context',
- 'π― Preparing strategy framework',
- 'π Generating educational content'
- ],
- insight: 'We\'re getting everything ready for your personalized AI strategy generation.',
- estimated_time: '2-3 minutes total'
- });
-
- // Show educational modal
- setShowEducationalModal(true);
-
- // Create basic strategy first
- const newStrategy = await createEnhancedStrategy(strategyData);
- console.log('Basic strategy created:', newStrategy);
-
- if (newStrategy && newStrategy.id) {
- console.log('Starting AI generation for strategy ID:', newStrategy.id);
-
- // Set a timeout for the entire process (5 minutes)
- const processTimeout = setTimeout(async () => {
- console.error('β° Strategy generation timeout after 5 minutes');
-
- // Try to check if the strategy was actually created
- try {
- const existingStrategy = await contentPlanningApi.getEnhancedStrategy(newStrategy.id.toString());
- if (existingStrategy) {
- console.log('β Strategy was created successfully despite SSE timeout');
- setCurrentStrategy(existingStrategy);
- setError('Strategy created successfully! The AI generation may still be running in the background. Check the Strategic Intelligence tab for detailed insights.');
- } else {
- setError('Strategy generation is taking longer than expected. The process may still be running in the background. Please check the Strategic Intelligence tab for results.');
- }
- } catch (checkError) {
- console.error('Error checking strategy status:', checkError);
- setError('Strategy generation is taking longer than expected. The process may still be running in the background. Please check the Strategic Intelligence tab for results.');
- }
-
- setShowEducationalModal(false);
- }, 5 * 60 * 1000); // 5 minutes
-
- // Add heartbeat monitoring
- let lastMessageTime = Date.now();
- const heartbeatInterval = setInterval(() => {
- const timeSinceLastMessage = Date.now() - lastMessageTime;
- if (timeSinceLastMessage > 30000) { // 30 seconds without message
- console.warn('β οΈ No SSE messages received for 30 seconds');
- setEducationalContent({
- title: 'π€ AI-Powered Strategy Generation',
- description: 'AI analysis is still running in the background. This may take a few more minutes.',
- details: [
- 'β³ Processing complex AI analysis',
- 'π Analyzing market data',
- 'π― Generating strategic insights',
- 'π Calculating performance predictions'
- ],
- insight: 'The AI is working on comprehensive analysis. This is normal for complex strategies.',
- estimated_time: 'Additional 1-2 minutes'
- });
- }
- }, 10000); // Check every 10 seconds
-
- // Use SSE endpoint for AI generation with educational content
- const eventSource = await contentPlanningApi.streamStrategyGeneration(Number(newStrategy.id));
-
- console.log('π SSE EventSource created:', eventSource);
- console.log('π SSE readyState:', eventSource.readyState);
-
- // Handle SSE data with proper parsing
- eventSource.onmessage = (event) => {
- try {
- console.log('π¨ Raw SSE message:', event.data);
-
- // Update last message time for heartbeat
- lastMessageTime = Date.now();
-
- // Parse the SSE data
- const data = JSON.parse(event.data);
- console.log('π¨ Parsed SSE data:', data);
- console.log('π¨ Message type analysis:', {
- hasStep: data.step !== undefined,
- hasProgress: data.progress !== undefined,
- hasEducationalContent: !!data.educational_content,
- hasError: !!data.error,
- hasSuccess: !!data.success,
- hasType: !!data.type,
- step: data.step,
- progress: data.progress,
- message: data.message
- });
-
- // Handle different types of messages
- if (data.error) {
- console.error('β SSE Error:', data.error);
- clearTimeout(processTimeout);
- clearInterval(heartbeatInterval);
- setError(`AI generation failed: ${data.error}`);
- setShowEducationalModal(false);
- eventSource.close();
- return;
- }
-
- // Handle step and progress updates (backend sends these)
- if (data.step !== undefined) {
- console.log('π’ Updating step:', data.step);
- // Calculate progress from step (each step is 10%)
- const stepProgress = Math.min(data.step * 10, 100);
- console.log('π Calculated progress from step:', stepProgress);
- setGenerationProgress(stepProgress);
- }
-
- // Handle explicit progress updates
- if (data.progress !== undefined) {
- console.log('π Updating progress:', data.progress);
- setGenerationProgress(data.progress);
- }
-
- // Handle educational content updates
- if (data.educational_content) {
- console.log('π Updating educational content:', data.educational_content);
- setEducationalContent(data.educational_content);
- }
-
- // Handle completion
- if (data.step === 10 && data.success) {
- console.log('β Strategy generation completed successfully!');
- clearTimeout(processTimeout);
- clearInterval(heartbeatInterval);
- setCurrentStrategy(data.strategy);
- setShowEducationalModal(false);
- setError('Strategy created successfully! Check the Strategic Intelligence tab for detailed insights.');
- eventSource.close();
- }
-
- // Handle educational content from AI service manager
- if (data.type === 'educational_content' && data.educational_content) {
- console.log('π AI Service educational content:', data.educational_content);
- setEducationalContent(data.educational_content);
- }
-
- // Handle success messages for individual steps
- if (data.success && data.message) {
- console.log('β Step completed:', data.message);
- // Progress is already updated above, just log the success
- }
-
- } catch (parseError) {
- console.error('β Error parsing SSE message:', parseError);
- console.error('Raw message:', event.data);
- }
- };
-
- // Handle SSE errors
- eventSource.onerror = (error) => {
- console.error('β SSE connection error:', error);
- console.error(' ReadyState:', eventSource.readyState);
-
- // Check connection state
- switch (eventSource.readyState) {
- case EventSource.CONNECTING:
- console.log('π SSE connection is connecting...');
- break;
- case EventSource.OPEN:
- console.log('β SSE connection is open');
- break;
- case EventSource.CLOSED:
- console.log('π SSE connection is closed');
- clearTimeout(processTimeout);
- clearInterval(heartbeatInterval);
- setError('Connection lost during AI generation. The process may still be running in the background. Please check the Strategic Intelligence tab for results.');
- setShowEducationalModal(false);
- break;
- }
- };
-
- // Handle SSE connection open
- eventSource.onopen = () => {
- console.log('β SSE connection opened successfully');
- console.log(' ReadyState:', eventSource.readyState);
- console.log(' URL:', eventSource.url);
-
- // Update educational content to show connection is established
- setEducationalContent({
- title: 'π Connection Established',
- description: 'Successfully connected to AI generation service. Starting analysis...',
- details: [
- 'β SSE connection active',
- 'π€ AI service ready',
- 'π Data processing initialized',
- 'π― Strategy generation starting'
- ],
- insight: 'The connection is now established and AI analysis is beginning.',
- estimated_time: '2-3 minutes total'
- });
- };
-
- } else {
- setError('Failed to create strategy or get strategy ID for AI generation.');
- console.error('Failed to create strategy or get strategy ID for AI generation.');
- setShowEducationalModal(false);
- }
- } catch (error: any) {
- console.error('Error in SSE strategy generation:', error);
- setError(`Error in strategy generation: ${error.message || 'Unknown error'}`);
- setShowEducationalModal(false);
- }
- };
-
- const handleSaveStrategy = async () => {
- try {
- setSaving(true);
- setError(null);
-
- const completionStats = getCompletionStats();
- const strategyData = {
- ...formData,
- completion_percentage: completionStats.completion_percentage,
- user_id: 1,
- name: formData.name || 'Enhanced Content Strategy',
- industry: formData.industry || 'General'
- };
-
- const newStrategy = await createEnhancedStrategy(strategyData);
- setCurrentStrategy(newStrategy);
- setError('Strategy saved successfully!');
- } catch (err: any) {
- setError(`Error saving strategy: ${err.message || 'Unknown error'}`);
- } finally {
- setSaving(false);
- }
- };
-
const handleReviewCategory = (categoryId: string) => {
setActiveCategory(activeCategory === categoryId ? null : categoryId);
};
@@ -519,75 +257,19 @@ const ContentStrategyBuilder: React.FC = () => {
{/* Error Alert */}
- {error && (
-
-
-
-
- }
- >
-
- Real data required
- {error || 'We could not auto-populate because required onboarding/analysis data is missing. Connect sources or complete onboarding, then retry.'}
-
-
- )}
+ autoPopulateFromOnboarding(true)}
+ onShowDataSourceTransparency={() => setShowDataSourceTransparency(true)}
+ />
- {/* Success Alert */}
- {!error && currentStrategy && (
-
- Strategy "{currentStrategy.name}" created successfully! Check the Strategic Intelligence tab for detailed insights.
-
- )}
-
- {/* Strategy Display */}
- {currentStrategy && (
-
-
- Created Strategy: {currentStrategy.name}
-
-
-
-
- Industry: {currentStrategy.industry}
-
-
- Completion: {currentStrategy.completion_percentage}%
-
-
-
-
- Created: {new Date(currentStrategy.created_at).toLocaleDateString()}
-
-
- ID: {currentStrategy.id}
-
-
-
-
-
-
-
- )}
-
- {categoryCompletionMessage && (
-
- {categoryCompletionMessage}
-
- )}
+ {/* Strategy Display and Success Alerts */}
+ window.location.href = '/content-planning?tab=strategic-intelligence'}
+ />
{/* Category Overview Panel */}
@@ -781,212 +463,41 @@ const ContentStrategyBuilder: React.FC = () => {
{/* Main Content Area */}
- {activeCategory ? (
-
- {/* Category Header */}
-
- {getCategoryIcon(activeCategory)}
-
- {activeCategory.split('_').map(word =>
- word.charAt(0).toUpperCase() + word.slice(1)
- ).join(' ')}
-
-
-
-
- {/* Educational Info Dialog */}
-
-
- {/* Category Fields */}
-
-
- {STRATEGIC_INPUT_FIELDS
- .filter(field => field.category === activeCategory)
- .map((field, index) => {
- // Determine grid size based on field type for better layout organization
- const type = field.type;
- const isWideField = type === 'json';
- const isMediumField = type === 'multiselect' || type === 'select' || type === 'text';
- const isCompactField = type === 'number' || type === 'boolean';
- const forceFullWidth = field.id === 'content_budget' || field.id === 'team_size';
-
- const gridMd = forceFullWidth ? 12 : (isWideField ? 12 : isMediumField ? 6 : 4);
- const gridLg = forceFullWidth ? 12 : (isWideField ? 12 : isMediumField ? 6 : 4);
- const gridSm = 12;
-
- return (
-
-
- updateFormField(field.id, value)}
- onValidate={() => validateFormField(field.id)}
- onShowTooltip={() => setShowTooltip(field.id)}
- onViewDataSource={() => setShowDataSourceTransparency(true)}
- accentColorKey={getCategoryColor(activeCategory) as any}
- isCompact={isCompactField}
- />
-
-
- );
- })}
-
-
-
- {/* Category Actions */}
-
- {(() => {
- const isReviewed = reviewedCategories.has(activeCategory);
- console.log('π Category review status:', {
- activeCategory,
- isReviewed,
- reviewedCategories: Array.from(reviewedCategories)
- });
- return !isReviewed ? (
-
- ) : (
- }
- sx={{ px: 2, py: 1 }}
- />
- );
- })()}
-
-
-
-
- ) : (
-
-
-
-
- Select a Category to Review
-
-
- Click on any category from the left panel to review and complete the fields.
-
-
-
- )}
+ setShowDataSourceTransparency(true)}
+ onConfirmCategoryReview={handleConfirmCategoryReviewWrapper}
+ onSetActiveCategory={setActiveCategory}
+ onSetShowEducationalInfo={setShowEducationalInfo}
+ getCategoryIcon={getCategoryIcon}
+ getCategoryColor={getCategoryColor}
+ getEducationalContent={getEducationalContent}
+ />
{/* Action Buttons */}
-
-
-
- }
- onClick={handleCreateStrategy}
- disabled={aiGenerating || reviewProgressPercentage < 20}
- >
- {aiGenerating ? 'Creating...' : 'Create Strategy'}
-
-
-
-
- }
- onClick={handleSaveStrategy}
- disabled={saving || reviewProgressPercentage < 30}
- >
- {saving ? 'Saving...' : 'Save Strategy'}
-
-
+
{/* AI Recommendations Modal */}
- {/* Educational Modal for Strategy Generation */}
-
+ educationalContent={educationalContent}
+ generationProgress={generationProgress}
+ />
{/* Data Source Transparency Modal */}