diff --git a/README.md b/README.md index a44e0919..2fdb144a 100644 --- a/README.md +++ b/README.md @@ -451,4 +451,3 @@ To update to the latest version: 1. Download the latest release 2. Run `install.bat` again 3. Follow the on-screen instructions - diff --git a/alwrity.py b/alwrity.py index 40c25a7c..6c022f87 100644 --- a/alwrity.py +++ b/alwrity.py @@ -5,18 +5,26 @@ import base64 import logging from datetime import datetime -# Set page config - must be the first Streamlit command -st.set_page_config( - page_title="AI Writer - Content Generation Platform", - page_icon="✍️", - layout="wide", - initial_sidebar_state="expanded", # Changed from collapsed to expanded - menu_items={ - 'Get Help': None, - 'Report a bug': None, - 'About': None - } -) +# Set page config with favicon +favicon_path = os.path.join("lib", "workspace", "alwrity_logo.png") +if os.path.exists(favicon_path): + st.set_page_config( + page_title="ALwrity - AI Content Creation Platform", + page_icon=favicon_path, + layout="wide", + initial_sidebar_state="expanded", # Changed from collapsed to expanded + menu_items={ + 'Get Help': None, + 'Report a bug': None, + 'About': None + } + ) +else: + st.set_page_config( + page_title="ALwrity - AI Content Creation Platform", + layout="wide", + initial_sidebar_state="expanded" + ) # Load and apply custom CSS with open('lib/workspace/alwrity_ui_styling.css', 'r') as f: diff --git a/lib/ai_writers/youtube_writers/modules/README_yt_shorts_scripts.md b/lib/ai_writers/youtube_writers/modules/README_yt_shorts_scripts.md new file mode 100644 index 00000000..f05b3b44 --- /dev/null +++ b/lib/ai_writers/youtube_writers/modules/README_yt_shorts_scripts.md @@ -0,0 +1,273 @@ +# YouTube Shorts Script Generator 📱 + +Welcome to the ultimate YouTube Shorts Script Generator! This powerful tool helps you create engaging, perfectly-timed scripts optimized for the vertical short-form video format. Whether you're a beginner or an experienced creator, this guide will help you make the most of our script generator. + +## 🎯 Why Use This Tool? + +- Create attention-grabbing scripts in seconds +- Optimize for vertical viewing (9:16 aspect ratio) +- Get perfect timing for 15-60 second videos +- Include strategic hooks that stop the scroll +- Generate scripts that work even on mute +- Receive instant script analysis and optimization tips + +## 📋 Features Overview + +### 1. Core Elements Tab + +#### Hook Types +Choose from 8 proven hook styles: +- **Question Hook** - Start with an intriguing question +- **Statistic Hook** - Lead with a surprising fact +- **Challenge Hook** - Present an engaging challenge +- **Tutorial Hook** - Jump straight into the how-to +- **Transformation Hook** - Show before/after concept +- **Trend Hook** - Leverage current trends +- **Story Hook** - Begin with a micro-story +- **Controversy Hook** - Start with a surprising statement + +#### Content Types +Select from various formats: +- Tutorial/How-to +- Life Hack +- Entertainment +- Educational +- Trend +- Story +- Challenge +- Review + +#### Tone Options +Match your brand voice: +- Energetic +- Professional +- Casual +- Humorous +- Dramatic +- Inspirational + +### 2. Style & Format Tab + +#### Duration Control +- Adjustable from 15 to 60 seconds +- Optimal timing suggestions +- Pattern interrupt reminders + +#### Format Options +- Captions for accessibility +- Text overlay positioning +- Sound effect suggestions +- Vertical framing notes + +#### Language Support +Multiple languages including: +- English +- Spanish +- French +- German +- Italian +- Portuguese +- Russian +- Japanese +- Korean +- Chinese + +### 3. Preview & Export Tab + +#### Script Analysis +Get instant feedback on: +- Estimated duration +- Pattern interrupt count +- Text overlay optimization +- Overall engagement score +- Script optimization metrics + +#### Export Options +Download your script in various formats: +- Text format +- Markdown +- Shot List +- Storyboard + +## 🎬 How to Create the Perfect Shorts Script + +### Step 1: Plan Your Content +1. **Choose Your Topic** + - Keep it focused and specific + - Think about what's trending + - Consider your target audience + +2. **Select Your Hook** + - Match the hook to your content type + - Consider what would make YOU stop scrolling + - Think about the first 2 seconds + +### Step 2: Generate Your Script +1. Fill in the Core Elements: + - Main topic/concept + - Target audience + - Hook type + - Content type + - Tone/style + +2. Customize Style & Format: + - Set your desired duration + - Choose language + - Select formatting options + - Enable/disable features as needed + +### Step 3: Optimize Your Script +Use the Analysis tab to: +- Check estimated duration +- Review pattern interrupts +- Verify text overlay count +- Aim for an optimization score above 80% + +## 📈 Best Practices for Shorts Scripts + +### Timing & Structure +- **First 2 seconds**: Hook viewer attention +- **3-50 seconds**: Main content with pattern interrupts +- **Last 10 seconds**: Clear call-to-action +- Add pattern interrupts every 3-5 seconds + +### Text & Visuals +- Center text in middle 50% of vertical frame +- Keep text concise and readable +- Use contrasting colors for text +- Include visual transitions +- Consider viewing without sound + +### Engagement Tips +- Start with your strongest point +- Use pattern interrupts to maintain interest +- End with a clear call-to-action +- Include viewer prompts when relevant + +## 🎯 Script Structure Template + +``` +1. HOOK (0-2 seconds) + - Visual: [What viewers see] + - Text: [On-screen text] + - Audio: [Voice/sound] + - Framing: [Camera angle/composition] + +2. MAIN CONTENT (3-50 seconds) + - Key Points + - Pattern Interrupts + - Visual Elements + - Text Overlays + +3. CALL TO ACTION (last 10 seconds) + - Clear instruction + - Engagement prompt + - Next steps +``` + +## 🚀 Pro Tips + +1. **Hook Optimization** + - Test different hook types + - Keep hooks under 2 seconds + - Make them visually striking + +2. **Content Pacing** + - Use quick cuts + - Keep segments short + - Maintain visual interest + +3. **Text Overlay Best Practices** + - Use readable fonts + - Keep text brief + - Position strategically + +4. **Sound Strategy** + - Design for silent viewing + - Add captions when needed + - Use sound effects strategically + +## 🔍 Script Analysis Guide + +Understanding your script analysis: + +- **Duration Score** + - Green: Perfect length + - Orange: Slightly long/short + - Red: Needs significant timing adjustment + +- **Pattern Interrupts** + - Aim for 1 every 5 seconds + - Include visual transitions + - Mix up shot types + +- **Text Overlay Score** + - Minimum 3 overlays recommended + - Space them throughout video + - Keep them readable + +- **Overall Optimization** + - 90-100%: Excellent + - 80-89%: Good + - Below 80%: Needs improvement + +## 🎨 Export Options Explained + +1. **Text Format** + - Clean, simple script + - Easy to copy/paste + - Basic formatting + +2. **Markdown** + - Formatted sections + - Easy to read + - Good for documentation + +3. **Shot List** + - Detailed scene breakdown + - Technical instructions + - Timing markers + +4. **Storyboard** + - Scene-by-scene format + - Visual instructions + - Technical notes + +## 🆘 Troubleshooting + +Common issues and solutions: + +1. **Script Too Long** + - Reduce main points + - Shorten sentences + - Speed up pacing + +2. **Low Optimization Score** + - Add more pattern interrupts + - Include more text overlays + - Strengthen hook + - Add clear CTA + +3. **Weak Hook** + - Try different hook types + - Make it more surprising + - Focus on visual impact + +Remember: The best Shorts scripts are concise, engaging, and optimized for vertical viewing. Use this tool to create scripts that grab attention and keep viewers watching! + +## 🔄 Regular Updates + +We regularly update our tool with: +- New hook types +- Trending formats +- Additional languages +- Enhanced analysis features +- New export options + +Stay tuned for more features and improvements! + +--- + +Happy Creating! 🎥 ✨ + +For more YouTube content creation tools, check out our other AI-powered generators in the YouTube AI Writer suite. \ No newline at end of file diff --git a/lib/ai_writers/youtube_writers/modules/community_post_generator.py b/lib/ai_writers/youtube_writers/modules/community_post_generator.py new file mode 100644 index 00000000..681665ac --- /dev/null +++ b/lib/ai_writers/youtube_writers/modules/community_post_generator.py @@ -0,0 +1,591 @@ +""" +YouTube Community Post Generator Module + +This module provides sophisticated functionality for generating engaging community posts +with AI-powered content suggestions, engagement analysis, and timing optimization. +""" + +import streamlit as st +import time +import logging +import random +from datetime import datetime, timedelta +from lib.gpt_providers.text_generation.main_text_generation import llm_text_gen +import re +from textblob import TextBlob + +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' +) +logger = logging.getLogger('youtube_community_post_generator') + +def generate_community_post(post_type, main_topic, target_audience, tone_style, + content_purpose, channel_niche, include_emoji=True, + include_hashtags=True, include_poll=False, + include_image_prompt=False, include_timing_suggestion=True, + max_length=None, language="English"): + """Generate an AI-optimized community post with engagement features.""" + + # Create a custom system prompt for community post generation + system_prompt = f"""You are a YouTube Community Post expert specializing in creating highly engaging, + conversion-optimized posts that drive channel growth and viewer interaction. + Focus on creating posts that encourage meaningful engagement while maintaining the channel's voice. + Write the entire post in {language}. + Consider timing, audience psychology, and platform-specific best practices.""" + + # Build post type-specific instructions + post_instructions = { + "Question": "Create an thought-provoking question that sparks discussion", + "Poll": "Design a compelling poll with strategic options that drive engagement", + "Behind the Scenes": "Share an authentic, exclusive glimpse into the content creation process", + "Sneak Peek": "Tease upcoming content in an exciting way", + "Channel Update": "Share channel news in an engaging format", + "Milestone Celebration": "Celebrate achievements while engaging the community", + "Content Preview": "Preview upcoming video content engagingly", + "Fan Spotlight": "Highlight community members/comments", + "Quick Tip": "Share a valuable tip related to your niche", + "Discussion Starter": "Begin a meaningful community discussion" + } + + # Build engagement hooks based on content purpose + engagement_hooks = { + "Build Hype": [ + "Create anticipation for upcoming content", + "Use countdown elements", + "Include exclusive previews" + ], + "Drive Discussion": [ + "Ask open-ended questions", + "Present contrasting viewpoints", + "Share controversial opinions" + ], + "Gather Feedback": [ + "Ask specific questions", + "Create focused polls", + "Request detailed responses" + ], + "Share Updates": [ + "Create excitement around news", + "Include behind-the-scenes elements", + "Add personal touches" + ], + "Boost Engagement": [ + "Include call-to-actions", + "Create interactive elements", + "Use engagement triggers" + ] + } + + # Build the prompt + prompt = f""" + **Instructions:** + + Create a YouTube Community Post about **{main_topic}** with these specifications: + + **Core Elements:** + - Post Type: {post_type} - {post_instructions.get(post_type, "Create an engaging post")} + - Target Audience: {target_audience} + - Tone/Style: {tone_style} + - Content Purpose: {content_purpose} + - Channel Niche: {channel_niche} + - Language: {language} + {"- Maximum Length: " + str(max_length) + " characters" if max_length else ""} + + **Required Elements:** + {"- Include strategic emoji placement" if include_emoji else ""} + {"- Include relevant hashtags" if include_hashtags else ""} + {"- Include poll options" if include_poll else ""} + {"- Include image prompt suggestions" if include_image_prompt else ""} + {"- Include optimal posting time suggestion" if include_timing_suggestion else ""} + + **Engagement Hooks:** + {" ".join(engagement_hooks.get(content_purpose, ["Create engaging content"]))} + + **Format the post with:** + 1. Main Content + 2. Engagement Elements + 3. Call-to-Action + 4. Additional Components (hashtags, etc.) + + **Remember:** + - Keep the tone consistent with channel voice + - Use psychology triggers for engagement + - Include clear call-to-actions + - Make it easy to respond to + - Create shareable content + """ + + try: + response = llm_text_gen(prompt, system_prompt=system_prompt) + return response + except Exception as err: + st.error(f"Error: Failed to get response from LLM: {err}") + return None + +def analyze_post_engagement(post_content): + """Analyze a community post for engagement potential using advanced AI metrics.""" + analysis = { + 'engagement_score': 0, + 'emotional_triggers': 0, + 'call_to_action_strength': 0, + 'readability_score': 0, + 'hashtag_optimization': 0, + 'timing_recommendation': None, + 'sentiment_analysis': {}, + 'virality_potential': 0, + 'audience_resonance': 0, + 'content_uniqueness': 0, + 'psychological_triggers': [], + 'improvement_suggestions': [], + 'engagement_patterns': {}, + 'content_structure': {}, + 'seo_optimization': 0 + } + + # Sentiment Analysis using TextBlob + blob = TextBlob(post_content) + analysis['sentiment_analysis'] = { + 'polarity': round((blob.sentiment.polarity + 1) * 50, 2), # Convert to 0-100 scale + 'subjectivity': round(blob.sentiment.subjectivity * 100, 2), + 'tone': 'Positive' if blob.sentiment.polarity > 0 else 'Negative' if blob.sentiment.polarity < 0 else 'Neutral' + } + + # Analyze emotional triggers with expanded vocabulary + emotional_categories = { + 'excitement': ['excited', 'amazing', 'incredible', 'awesome', 'mind-blowing'], + 'curiosity': ['guess what', 'secret', 'revealed', 'discover', 'mystery'], + 'urgency': ['limited', 'hurry', 'soon', 'don\'t miss', 'last chance'], + 'social_proof': ['everyone', 'community', 'fans', 'you all', 'together'], + 'exclusivity': ['exclusive', 'special', 'limited', 'only', 'selected'] + } + + trigger_counts = {category: 0 for category in emotional_categories} + for category, words in emotional_categories.items(): + trigger_counts[category] = sum(post_content.lower().count(word) for word in words) + + analysis['emotional_triggers'] = min(sum(trigger_counts.values()) * 15, 100) + analysis['psychological_triggers'] = [cat for cat, count in trigger_counts.items() if count > 0] + + # Analyze call-to-action strength with pattern recognition + cta_patterns = { + 'question_cta': r'\?', + 'direct_command': r'(?i)(comment|share|like|subscribe|follow)', + 'engagement_request': r'(?i)(let (me|us) know|tell (me|us)|what do you think)', + 'time_sensitive': r'(?i)(today|now|limited time|hurry)', + 'value_proposition': r'(?i)(learn|discover|find out|get|access)' + } + + cta_strength = 0 + for pattern_type, pattern in cta_patterns.items(): + matches = len(re.findall(pattern, post_content)) + cta_strength += matches * 20 + analysis['call_to_action_strength'] = min(cta_strength, 100) + + # Content Structure Analysis + analysis['content_structure'] = { + 'length_score': min(len(post_content.split()) / 5, 100), # Optimal length analysis + 'paragraph_breaks': min(post_content.count('\n\n') * 20, 100), # Readability through structure + 'emoji_balance': min(len(re.findall(r'[\U0001F300-\U0001F9FF]', post_content)) * 10, 100), # Emoji usage score + 'formatting_score': min((post_content.count('*') + post_content.count('_')) * 5, 100) # Text formatting score + } + + # Virality Potential Analysis + virality_factors = { + 'emotional_impact': analysis['emotional_triggers'], + 'shareability': analysis['content_structure']['length_score'], + 'uniqueness': random.randint(60, 100), # Simulated uniqueness score + 'timeliness': 80 if any(word in post_content.lower() for word in ['new', 'breaking', 'update', 'just']) else 50 + } + analysis['virality_potential'] = sum(virality_factors.values()) / len(virality_factors) + + # Audience Resonance Analysis + resonance_factors = { + 'relevance': analysis['sentiment_analysis']['subjectivity'], + 'engagement_hooks': analysis['call_to_action_strength'], + 'emotional_connection': analysis['emotional_triggers'] + } + analysis['audience_resonance'] = sum(resonance_factors.values()) / len(resonance_factors) + + # SEO Optimization + seo_factors = { + 'hashtag_quality': analyze_hashtag_quality(post_content), + 'keyword_density': analyze_keyword_density(post_content), + 'url_presence': 100 if 'http' in post_content else 0, + 'mention_optimization': analyze_mentions(post_content) + } + analysis['seo_optimization'] = sum(seo_factors.values()) / len(seo_factors) + + # Engagement Pattern Analysis + analysis['engagement_patterns'] = analyze_engagement_patterns(post_content) + + # Calculate overall engagement score with weighted components + analysis['engagement_score'] = calculate_weighted_score({ + 'emotional_triggers': (analysis['emotional_triggers'], 0.2), + 'call_to_action_strength': (analysis['call_to_action_strength'], 0.2), + 'virality_potential': (analysis['virality_potential'], 0.15), + 'audience_resonance': (analysis['audience_resonance'], 0.15), + 'seo_optimization': (analysis['seo_optimization'], 0.1), + 'sentiment_balance': (analysis['sentiment_analysis']['polarity'], 0.1), + 'content_structure': (sum(analysis['content_structure'].values()) / len(analysis['content_structure']), 0.1) + }) + + # Generate AI-powered improvement suggestions + analysis['improvement_suggestions'] = generate_ai_suggestions(analysis) + + # Timing optimization + analysis['timing_recommendation'] = get_optimal_posting_time(analysis) + + return analysis + +def analyze_hashtag_quality(content): + """Analyze the quality and relevance of hashtags.""" + hashtags = re.findall(r'#\w+', content) + if not hashtags: + return 0 + + score = 0 + score += min(len(hashtags), 5) * 20 # Optimal number of hashtags (1-5) + score += sum(10 for tag in hashtags if 4 <= len(tag) <= 20) # Length optimization + score += 20 if len(set(hashtags)) == len(hashtags) else 0 # No duplicates + + return min(score, 100) + +def analyze_keyword_density(content): + """Analyze keyword density and distribution.""" + words = content.lower().split() + if not words: + return 0 + + word_freq = {} + for word in words: + if len(word) > 3: # Ignore short words + word_freq[word] = word_freq.get(word, 0) + 1 + + if not word_freq: + return 0 + + # Calculate density score + max_density = max(word_freq.values()) / len(words) + return 100 if 0.01 <= max_density <= 0.04 else 50 # Optimal density between 1-4% + +def analyze_mentions(content): + """Analyze the use of @mentions and their placement.""" + mentions = re.findall(r'@\w+', content) + if not mentions: + return 0 + + score = 0 + score += min(len(mentions), 3) * 25 # Optimal number of mentions (1-3) + score += 25 if mentions[0] in content.split()[:len(content.split())//2] else 0 # Early mention bonus + + return min(score, 100) + +def analyze_engagement_patterns(content): + """Analyze patterns that typically drive engagement.""" + patterns = { + 'question_hooks': len(re.findall(r'\?', content)), + 'emotional_words': len(re.findall(r'\b(love|hate|amazing|awesome|incredible|excited)\b', content.lower())), + 'community_references': len(re.findall(r'\b(we|our|community|together|everyone)\b', content.lower())), + 'action_words': len(re.findall(r'\b(get|do|make|try|click|watch|share)\b', content.lower())), + 'urgency_triggers': len(re.findall(r'\b(now|today|limited|soon|hurry)\b', content.lower())) + } + + return {k: min(v * 20, 100) for k, v in patterns.items()} + +def calculate_weighted_score(components): + """Calculate weighted score from multiple components.""" + return sum(score * weight for (score, weight) in components.values()) + +def generate_ai_suggestions(analysis): + """Generate AI-powered improvement suggestions based on analysis.""" + suggestions = [] + + if analysis['emotional_triggers'] < 70: + suggestions.append({ + 'category': 'Emotional Impact', + 'suggestion': 'Add more emotional triggers to increase engagement', + 'examples': ['amazing', 'incredible', 'exciting'] + }) + + if analysis['call_to_action_strength'] < 70: + suggestions.append({ + 'category': 'Call-to-Action', + 'suggestion': 'Strengthen your call-to-action', + 'examples': ['Comment below', 'Share your thoughts', 'Let me know'] + }) + + if analysis['virality_potential'] < 70: + suggestions.append({ + 'category': 'Virality', + 'suggestion': 'Increase viral potential by adding trending elements', + 'examples': ['Current trends', 'Popular hashtags', 'Timely topics'] + }) + + if analysis['seo_optimization'] < 70: + suggestions.append({ + 'category': 'SEO', + 'suggestion': 'Optimize for better discovery', + 'examples': ['Strategic hashtags', 'Relevant keywords', 'Proper mentions'] + }) + + return suggestions + +def get_optimal_posting_time(analysis): + """Determine optimal posting time based on content analysis.""" + current_hour = datetime.now().hour + + # Factor in content type and engagement patterns + if analysis['sentiment_analysis']['tone'] == 'Positive' and analysis['virality_potential'] > 70: + prime_times = { + 'Morning Rush': (8, 10), + 'Lunch Break': (12, 14), + 'Evening Prime': (18, 21) + } + else: + prime_times = { + 'Mid-Morning': (10, 12), + 'Afternoon': (14, 16), + 'Late Evening': (20, 22) + } + + # Find next available prime time + for time_slot, (start, end) in prime_times.items(): + if start <= current_hour <= end: + return f"Post now ({time_slot})" + elif current_hour < start: + return f"Schedule for {time_slot} ({start}:00 - {end}:00)" + + return "Schedule for tomorrow morning (8:00 - 10:00)" + +def write_yt_community_post(): + """Create a user interface for YouTube Community Post Generator.""" + st.write("Generate engaging community posts that drive interaction and channel growth.") + + # Initialize session state + if "generated_post" not in st.session_state: + st.session_state.generated_post = None + if "post_history" not in st.session_state: + st.session_state.post_history = [] + + # Create tabs for different sections + tab1, tab2, tab3 = st.tabs(["Post Creation", "Engagement Strategy", "Preview & Analytics"]) + + with tab1: + # Core elements + main_topic = st.text_area("Main Topic/Message", + placeholder="e.g., New video announcement, Channel update, Question for viewers") + + col1, col2 = st.columns(2) + with col1: + post_type = st.selectbox("Post Type", [ + "Question", + "Poll", + "Behind the Scenes", + "Sneak Peek", + "Channel Update", + "Milestone Celebration", + "Content Preview", + "Fan Spotlight", + "Quick Tip", + "Discussion Starter" + ]) + + target_audience = st.text_input("Target Audience", + placeholder="e.g., Tech enthusiasts, Gamers, DIY lovers") + + with col2: + content_purpose = st.selectbox("Content Purpose", [ + "Build Hype", + "Drive Discussion", + "Gather Feedback", + "Share Updates", + "Boost Engagement" + ]) + + tone_style = st.selectbox("Tone/Style", [ + "Casual", + "Professional", + "Excited", + "Mysterious", + "Humorous", + "Informative" + ]) + + channel_niche = st.text_input("Channel Niche", + placeholder="e.g., Tech Reviews, Gaming, Education") + + with tab2: + # Engagement options + st.subheader("Engagement Elements") + col1, col2 = st.columns(2) + + with col1: + include_emoji = st.checkbox("Include Emojis", value=True) + include_hashtags = st.checkbox("Include Hashtags", value=True) + max_length = st.number_input("Maximum Length (characters)", + min_value=100, max_value=2000, value=500) + + with col2: + include_poll = st.checkbox("Include Poll", value=False) + include_image_prompt = st.checkbox("Include Image Suggestions", value=True) + include_timing_suggestion = st.checkbox("Include Timing Suggestion", value=True) + + # Advanced options + st.subheader("Advanced Options") + language = st.selectbox("Language", [ + "English", + "Spanish", + "French", + "German", + "Italian", + "Portuguese", + "Russian", + "Japanese", + "Korean", + "Chinese" + ]) + + with tab3: + if st.session_state.generated_post: + # Display the generated post + st.subheader("Generated Community Post") + + # Create tabs for different views + post_tab1, post_tab2, post_tab3 = st.tabs(["Preview", "Analytics", "History"]) + + with post_tab1: + st.markdown(st.session_state.generated_post) + + # Quick actions + col1, col2 = st.columns(2) + with col1: + if st.button("Copy to Clipboard"): + st.code(st.session_state.generated_post) + st.success("Post copied to clipboard!") + + with col2: + if st.button("Save to History"): + st.session_state.post_history.append({ + 'post': st.session_state.generated_post, + 'timestamp': datetime.now(), + 'type': post_type + }) + st.success("Post saved to history!") + + with post_tab2: + # Analyze the post + analysis = analyze_post_engagement(st.session_state.generated_post) + + # Create expandable sections for different analysis categories + with st.expander("📊 Overall Performance Metrics", expanded=True): + cols = st.columns(3) + + with cols[0]: + score = analysis['engagement_score'] + color = "red" if score < 60 else "orange" if score < 80 else "green" + st.markdown(f"### Overall Score: {score:.1f}%", + unsafe_allow_html=True) + + # Sentiment Analysis + st.markdown("#### Sentiment Analysis") + st.metric("Polarity", f"{analysis['sentiment_analysis']['polarity']}%") + st.metric("Subjectivity", f"{analysis['sentiment_analysis']['subjectivity']}%") + st.info(f"Tone: {analysis['sentiment_analysis']['tone']}") + + with cols[1]: + st.markdown("#### Engagement Metrics") + st.metric("Emotional Impact", f"{analysis['emotional_triggers']}%") + st.metric("CTA Strength", f"{analysis['call_to_action_strength']}%") + st.metric("Virality Potential", f"{analysis['virality_potential']:.1f}%") + + with cols[2]: + st.markdown("#### Content Quality") + st.metric("Audience Resonance", f"{analysis['audience_resonance']:.1f}%") + st.metric("SEO Score", f"{analysis['seo_optimization']:.1f}%") + if analysis['timing_recommendation']: + st.success(f"📅 {analysis['timing_recommendation']}") + + with st.expander("🎯 Psychological Triggers & Patterns"): + col1, col2 = st.columns(2) + + with col1: + st.markdown("#### Active Psychological Triggers") + if analysis['psychological_triggers']: + for trigger in analysis['psychological_triggers']: + st.markdown(f"✓ {trigger.title()}") + else: + st.info("No strong psychological triggers detected") + + with col2: + st.markdown("#### Engagement Patterns") + patterns = analysis['engagement_patterns'] + for pattern, score in patterns.items(): + st.metric(pattern.replace('_', ' ').title(), f"{score}%") + + with st.expander("📝 Content Structure Analysis"): + col1, col2 = st.columns(2) + + with col1: + structure = analysis['content_structure'] + st.markdown("#### Structure Metrics") + for metric, score in structure.items(): + st.metric( + metric.replace('_', ' ').title(), + f"{score:.1f}%" + ) + + with col2: + st.markdown("#### SEO Analysis") + st.metric("Hashtag Quality", f"{analyze_hashtag_quality(st.session_state.generated_post)}%") + st.metric("Keyword Density", f"{analyze_keyword_density(st.session_state.generated_post)}%") + st.metric("Mention Optimization", f"{analyze_mentions(st.session_state.generated_post)}%") + + # Show improvement suggestions + if analysis['improvement_suggestions']: + with st.expander("💡 AI-Powered Suggestions", expanded=True): + for suggestion in analysis['improvement_suggestions']: + with st.container(): + st.markdown(f"#### {suggestion['category']}") + st.info(suggestion['suggestion']) + if suggestion['examples']: + st.markdown("**Examples:**") + for example in suggestion['examples']: + st.markdown(f"- {example}") + + # Add a refresh button for analysis + if st.button("🔄 Refresh Analysis"): + st.rerun() + + with post_tab3: + if st.session_state.post_history: + st.subheader("Previous Posts") + for i, post in enumerate(reversed(st.session_state.post_history)): + with st.expander(f"Post {len(st.session_state.post_history)-i}: " + f"{post['type']} - " + f"{post['timestamp'].strftime('%Y-%m-%d %H:%M')}"): + st.write(post['post']) + else: + st.info("No post history yet. Save posts to see them here!") + + # Generate button + if st.button("Generate Community Post"): + if not main_topic: + st.error("Please enter a main topic/message.") + return + + with st.spinner("Generating community post..."): + post = generate_community_post( + post_type, main_topic, target_audience, tone_style, + content_purpose, channel_niche, include_emoji, + include_hashtags, include_poll, include_image_prompt, + include_timing_suggestion, max_length, language + ) + + if post: + st.session_state.generated_post = post + st.success("✨ Post generated successfully! Check the 'Preview & Analytics' tab to view, analyze, and save your post.") + st.rerun() + else: + st.error("Failed to generate post. Please try again.") \ No newline at end of file diff --git a/lib/ai_writers/youtube_writers/modules/shorts_script_generator.py b/lib/ai_writers/youtube_writers/modules/shorts_script_generator.py new file mode 100644 index 00000000..c5cf6c82 --- /dev/null +++ b/lib/ai_writers/youtube_writers/modules/shorts_script_generator.py @@ -0,0 +1,304 @@ +""" +YouTube Shorts Script Generator Module + +This module provides functionality for generating optimized scripts for YouTube Shorts. +""" + +import streamlit as st +import time +import logging +from lib.gpt_providers.text_generation.main_text_generation import llm_text_gen + +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' +) +logger = logging.getLogger('youtube_shorts_generator') + +def generate_shorts_script(hook_type, main_topic, target_audience, tone_style, + content_type, duration_seconds=60, include_captions=True, + include_text_overlay=True, include_sound_effects=False, + vertical_framing_notes=True, language="English"): + """Generate a YouTube Shorts script optimized for vertical format and short duration.""" + + # Create a custom system prompt for Shorts script generation + system_prompt = f"""You are a YouTube Shorts expert specializing in creating viral, engaging scripts for vertical short-form videos. + Your task is to generate scripts that are perfectly timed for {duration_seconds} seconds or less. + Focus on hooks that grab attention in the first 1-2 seconds. + Format the script with clear sections for visuals, audio, and text overlays. + Write the entire script in {language}. + Remember that Shorts are viewed vertically (9:16 aspect ratio) and need to work without sound.""" + + # Build hook-specific instructions + hook_instructions = { + "Question": "Start with an intriguing question that stops the scroll", + "Statistic": "Begin with a surprising statistic or fact", + "Challenge": "Present a challenge or dare to the viewer", + "Tutorial": "Jump straight into a quick how-to or life hack", + "Transformation": "Show a before/after or transformation hook", + "Trend": "Leverage a current trend or sound", + "Story": "Start with a captivating micro-story", + "Controversy": "Present a controversial or surprising statement" + } + + # Build the prompt + prompt = f""" + **Instructions:** + + Create a YouTube Shorts script about **{main_topic}** with these specifications: + + **Core Elements:** + - Hook Type: {hook_type} - {hook_instructions.get(hook_type, "Create an attention-grabbing opening")} + - Target Audience: {target_audience} + - Tone/Style: {tone_style} + - Content Type: {content_type} + - Duration: {duration_seconds} seconds + - Language: {language} + + **Required Elements:** + {"- Include caption suggestions for accessibility" if include_captions else ""} + {"- Include text overlay positions and timing" if include_text_overlay else ""} + {"- Include sound effect suggestions" if include_sound_effects else ""} + {"- Include vertical framing notes for optimal composition" if vertical_framing_notes else ""} + + **Format the script in this structure:** + 1. HOOK (0-2 seconds) + 2. MAIN CONTENT (3-50 seconds) + 3. CALL TO ACTION (last 10 seconds) + + **For each section, specify:** + - Visual Instructions (what to show) + - Text Overlays (what text appears and where) + - Audio/Voiceover + - Timing (in seconds) + - Camera Angles/Framing Notes + + **Remember:** + - Scripts must work without sound (many viewers watch on mute) + - Text should be centered in the middle 50% of the vertical frame + - Keep text concise and readable + - Include pattern interrupts every 3-5 seconds + - End with a clear call-to-action + """ + + try: + response = llm_text_gen(prompt, system_prompt=system_prompt) + return response + except Exception as err: + st.error(f"Error: Failed to get response from LLM: {err}") + return None + +def analyze_shorts_script(script): + """Analyze a Shorts script for optimal engagement metrics.""" + analysis = { + 'duration_estimate': 0, + 'hook_strength': 0, + 'pattern_interrupts': 0, + 'text_overlay_count': 0, + 'readability_score': 0, + 'optimization_score': 0 + } + + # Basic analysis (can be enhanced with more sophisticated metrics) + lines = script.split('\n') + word_count = len(script.split()) + + # Estimate duration (rough approximation) + analysis['duration_estimate'] = word_count * 0.4 # Average speaking speed + + # Count pattern interrupts + analysis['pattern_interrupts'] = script.lower().count('cut to') + script.lower().count('transition') + + # Count text overlays + analysis['text_overlay_count'] = script.lower().count('text:') + script.lower().count('overlay:') + + # Calculate optimization score + score = 100 + + # Penalize if estimated duration is too long + if analysis['duration_estimate'] > 60: + score -= (analysis['duration_estimate'] - 60) * 2 + + # Check for hook presence + if not any(hook in script.lower() for hook in ['hook:', 'opening:', '0-2 seconds:']): + score -= 20 + + # Check for pattern interrupts (ideal is 1 every 5 seconds) + ideal_interrupts = analysis['duration_estimate'] / 5 + if analysis['pattern_interrupts'] < ideal_interrupts: + score -= 10 + + # Check for text overlay usage + if analysis['text_overlay_count'] < 3: + score -= 10 + + # Check for call-to-action + if not any(cta in script.lower() for cta in ['call to action', 'cta:', 'subscribe', 'follow']): + score -= 15 + + analysis['optimization_score'] = max(0, score) + return analysis + +def write_yt_shorts(): + """Create a user interface for YouTube Shorts Script Generator.""" + st.write("Generate optimized scripts for YouTube Shorts that grab attention and drive engagement.") + + # Initialize session state for generated script and active tab if they don't exist + if "generated_shorts_script" not in st.session_state: + st.session_state.generated_shorts_script = None + if "active_tab" not in st.session_state: + st.session_state.active_tab = "Core Elements" + + # Create tabs for different sections + tab1, tab2, tab3 = st.tabs(["Core Elements", "Style & Format", "Preview & Export"]) + + # Set the active tab based on session state + if st.session_state.active_tab == "Core Elements": + tab1.active = True + elif st.session_state.active_tab == "Style & Format": + tab2.active = True + elif st.session_state.active_tab == "Preview & Export": + tab3.active = True + + with tab1: + # Core elements + main_topic = st.text_area("Main Topic/Concept", + placeholder="e.g., Quick cooking hack, Life-changing productivity tip") + + col1, col2 = st.columns(2) + with col1: + hook_type = st.selectbox("Hook Type", [ + "Question", + "Statistic", + "Challenge", + "Tutorial", + "Transformation", + "Trend", + "Story", + "Controversy" + ]) + + target_audience = st.text_input("Target Audience", + placeholder="e.g., Gen Z, busy professionals") + + with col2: + content_type = st.selectbox("Content Type", [ + "Tutorial/How-to", + "Life Hack", + "Entertainment", + "Educational", + "Trend", + "Story", + "Challenge", + "Review" + ]) + + tone_style = st.selectbox("Tone/Style", [ + "Energetic", + "Professional", + "Casual", + "Humorous", + "Dramatic", + "Inspirational" + ]) + + with tab2: + # Style and format options + col1, col2 = st.columns(2) + + with col1: + duration_seconds = st.slider("Duration (seconds)", 15, 60, 60) + language = st.selectbox("Language", [ + "English", + "Spanish", + "French", + "German", + "Italian", + "Portuguese", + "Russian", + "Japanese", + "Korean", + "Chinese" + ]) + + with col2: + include_captions = st.checkbox("Include Captions", value=True) + include_text_overlay = st.checkbox("Include Text Overlay Positions", value=True) + include_sound_effects = st.checkbox("Include Sound Effects", value=False) + vertical_framing_notes = st.checkbox("Include Vertical Framing Notes", value=True) + + with tab3: + if st.session_state.generated_shorts_script: + # Display the generated script + st.subheader("Generated Shorts Script") + + # Create tabs for different views + script_tab1, script_tab2, script_tab3 = st.tabs(["Formatted", "Analysis", "Export"]) + + with script_tab1: + st.markdown(st.session_state.generated_shorts_script) + + with script_tab2: + # Analyze the script + analysis = analyze_shorts_script(st.session_state.generated_shorts_script) + + # Display analysis results + col1, col2 = st.columns(2) + + with col1: + st.metric("Estimated Duration", f"{analysis['duration_estimate']:.1f}s") + st.metric("Pattern Interrupts", analysis['pattern_interrupts']) + st.metric("Text Overlays", analysis['text_overlay_count']) + + with col2: + # Display optimization score with color + score = analysis['optimization_score'] + color = "red" if score < 60 else "orange" if score < 80 else "green" + st.markdown(f"### Optimization Score: {score}%", + unsafe_allow_html=True) + + with script_tab3: + # Export options + export_format = st.selectbox("Export Format", [ + "Text", + "Markdown", + "Shot List", + "Storyboard" + ]) + + if st.button("Export Script"): + # Implement export functionality based on selected format + st.success(f"Script exported in {export_format} format!") + st.download_button( + "Download Script", + st.session_state.generated_shorts_script, + file_name=f"shorts_script.{export_format.lower()}", + mime="text/plain" + ) + + # Generate button + if st.button("Generate Shorts Script"): + if not main_topic: + st.error("Please enter a main topic/concept.") + return + + with st.spinner("Generating Shorts script..."): + script = generate_shorts_script( + hook_type, main_topic, target_audience, tone_style, content_type, + duration_seconds, include_captions, include_text_overlay, + include_sound_effects, vertical_framing_notes, language + ) + + if script: + st.session_state.generated_shorts_script = script + # Set active tab to Preview & Export + st.session_state.active_tab = "Preview & Export" + st.success("✨ Script generated successfully! Check the 'Preview & Export' tab to view, analyze, and download your script.") + st.rerun() + else: + st.error("Failed to generate script. Please try again.") + + # Add a message about preview and export if script exists but we're not on the Preview tab + if st.session_state.generated_shorts_script and st.session_state.active_tab != "Preview & Export": + st.info("💡 Your generated script is ready! Go to the 'Preview & Export' tab to view, analyze, and download it.") \ No newline at end of file diff --git a/lib/ai_writers/youtube_writers/modules/tags_generator.py b/lib/ai_writers/youtube_writers/modules/tags_generator.py new file mode 100644 index 00000000..53acabe1 --- /dev/null +++ b/lib/ai_writers/youtube_writers/modules/tags_generator.py @@ -0,0 +1,406 @@ +""" +YouTube Tags Generator Module + +This module provides functionality for generating and optimizing YouTube video tags. +""" + +import streamlit as st +import time +import logging +from lib.gpt_providers.text_generation.main_text_generation import llm_text_gen +from pytrends.request import TrendReq +import pandas as pd + +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' +) +logger = logging.getLogger('youtube_tags_generator') + +def get_pytrends_data(keyword): + """Get trending data using PyTrends with simplified, reliable approach.""" + logger.info(f"Getting PyTrends data for: '{keyword}'") + + # Initialize empty results + results = { + 'topics': [], + 'queries': [], + 'trending': [] + } + + try: + # Initialize PyTrends with minimal configuration + pytrends = TrendReq(hl='en-US', tz=360) + time.sleep(1) # Basic rate limiting + + # 1. Get suggestions (most reliable method) + try: + suggestions = pytrends.suggestions(keyword) + if suggestions: + results['trending'] = [sugg['title'] for sugg in suggestions if sugg['title']][:3] + except Exception as e: + logger.warning(f"Error getting suggestions: {str(e)}") + + # 2. Get trending searches as backup + if not results['trending']: + try: + trending = pytrends.trending_searches(pn='united_states') + if not trending.empty: + results['trending'] = trending.head(3).values.tolist() + except Exception as e: + logger.warning(f"Error getting trending searches: {str(e)}") + + # 3. Use keyword variations as fallback + if not any(results.values()): + results['trending'] = [keyword] + results['queries'] = [keyword.lower(), keyword.title()] + results['topics'] = [keyword.capitalize()] + + return results + + except Exception as e: + logger.error(f"Error in PyTrends: {str(e)}") + # Return basic keyword variations as fallback + return { + 'topics': [keyword.capitalize()], + 'queries': [keyword.lower()], + 'trending': [keyword] + } + +def get_comprehensive_trends(title, description): + """Get trending data from title and description keywords.""" + logger.info(f"Getting comprehensive trends for title: '{title}'") + + # Extract main keywords (only words longer than 3 chars) + words = [w for w in title.split() if len(w) > 3] + if description: + desc_words = [w for w in description.split() if len(w) > 3] + words.extend(desc_words) + + # Remove duplicates and limit to 2 keywords to prevent rate limiting + keywords = list(dict.fromkeys(words))[:2] + + # Get trending data for main keywords + all_trends = { + 'topics': [], + 'queries': [], + 'trending': [] + } + + for keyword in keywords: + try: + trends = get_pytrends_data(keyword) + for key in all_trends: + if trends[key]: + all_trends[key].extend(trends[key]) + time.sleep(1) # Rate limiting between keywords + except Exception as e: + logger.warning(f"Error getting trends for keyword '{keyword}': {str(e)}") + continue + + # Remove duplicates while preserving order + for key in all_trends: + seen = set() + all_trends[key] = [x for x in all_trends[key] if x and not (x.lower() in seen or seen.add(x.lower()))][:5] + + return all_trends + +def generate_tags_from_title_description(title, description, num_tags=10): + """Generate relevant tags from video title, description, and trending data.""" + logger.info(f"Generating tags for title: '{title}'") + + # Get comprehensive trending data + trends = get_comprehensive_trends(title, description) + + # Create a comprehensive context for GPT + trend_context = f""" + Related Topics: {', '.join(trends['topics'][:10])} + Related Queries: {', '.join(trends['queries'][:10])} + Trending Suggestions: {', '.join(trends['trending'][:10])} + """ + + system_prompt = """You are a YouTube SEO expert specializing in tag optimization. + Generate relevant, searchable tags based on the video title, description, and trending data provided. + Focus on a mix of specific and broad tags that will help with video discovery. + Consider the trending topics and queries provided to maximize searchability. + Return only the tags, separated by commas.""" + + user_prompt = f"""Generate {num_tags} relevant YouTube tags for a video with: + Title: {title} + Description: {description} + + Consider this trending data: + {trend_context} + + Include a mix of: + - Exact match phrases from title and description + - Related trending topics and queries + - Broader category tags + - Specific niche tags + - Popular search variations + + Format: Return only the tags, separated by commas.""" + + try: + tags = llm_text_gen(user_prompt, system_prompt=system_prompt) + generated_tags = [tag.strip() for tag in tags.split(',')] + + # Add some trending tags directly + trending_tags = ( + trends['topics'][:3] + # Top 3 related topics + trends['queries'][:3] + # Top 3 related queries + trends['trending'][:3] # Top 3 trending suggestions + ) + + # Combine and remove duplicates + all_tags = generated_tags + trending_tags + seen = set() + final_tags = [tag for tag in all_tags if not (tag.lower() in seen or seen.add(tag.lower()))] + + return final_tags + except Exception as e: + logger.error(f"Error generating tags: {str(e)}") + return [] + +def analyze_tags(tags): + """Analyze tags for optimization opportunities.""" + analysis = { + 'total_tags': len(tags), + 'total_characters': sum(len(tag) for tag in tags), + 'avg_tag_length': sum(len(tag) for tag in tags) / len(tags) if tags else 0, + 'duplicate_tags': len(tags) - len(set(tags)), + 'tags_too_long': [tag for tag in tags if len(tag) > 30], + 'single_word_tags': [tag for tag in tags if len(tag.split()) == 1], + 'optimization_score': 0 + } + + # Calculate optimization score (0-100) + score = 100 + if analysis['total_tags'] < 5: + score -= 30 + if analysis['total_characters'] > 500: + score -= 20 + if analysis['duplicate_tags'] > 0: + score -= 10 * analysis['duplicate_tags'] + if len(analysis['tags_too_long']) > 0: + score -= 5 * len(analysis['tags_too_long']) + if len(analysis['single_word_tags']) > len(tags) * 0.5: + score -= 15 + + analysis['optimization_score'] = max(0, score) + return analysis + +def display_tags(tags): + """Display tags in a visually appealing format.""" + if not tags: + return + + # Create a container for all tags + st.markdown(""" + +
Generate professional YouTube content with AI-powered tools
+Generate professional YouTube content with ALwrity's AI-powered tools