Youtube AI Writer Tools like yt_shorts_scripts, tags_generator, community_post_generator, shorts_script_generator

This commit is contained in:
ajaysi
2025-04-10 11:42:34 +05:30
parent d734c66f1a
commit 8ac2095ac4
9 changed files with 1932 additions and 64 deletions

View File

@@ -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

View File

@@ -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:

View File

@@ -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.

View File

@@ -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: <span style='color: {color}'>{score:.1f}%</span>",
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.")

View File

@@ -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: <span style='color: {color}'>{score}%</span>",
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.")

View File

@@ -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("""
<style>
.tag-container {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 16px;
padding: 12px;
background-color: #f8f9fa;
border-radius: 8px;
}
.tag {
display: inline-flex;
align-items: center;
background-color: #f0f2f6;
border-radius: 16px;
padding: 6px 12px;
font-size: 13px;
color: #2c3e50;
border: 1px solid #e6e9ef;
white-space: nowrap;
transition: all 0.2s ease;
}
.tag:hover {
background-color: #e6e9ef;
border-color: #d1d5db;
transform: translateY(-1px);
}
</style>
<div class="tag-container">
""", unsafe_allow_html=True)
# Display tags
for tag in tags:
st.markdown(f'<div class="tag">{tag}</div>', unsafe_allow_html=True)
st.markdown('</div>', unsafe_allow_html=True)
# Display tag count and character count
tags_text = ", ".join(tags)
char_count = len(tags_text)
col1, col2 = st.columns(2)
with col1:
st.caption(f"Total tags: {len(tags)}")
with col2:
st.caption(f"Characters: {char_count}/500")
def write_yt_tags():
"""Create a user interface for YouTube Tags Generator."""
logger.info("Initializing YouTube Tags Generator UI")
st.write("Generate optimized tags for your videos with trending tag suggestions to improve discoverability.")
# Initialize session state
if "generated_tags" not in st.session_state:
st.session_state.generated_tags = None
if "tag_analysis" not in st.session_state:
st.session_state.tag_analysis = None
# Create tabs for different sections
tab1, tab2, tab3 = st.tabs(["Quick Generate", "Advanced Options", "Analysis"])
with tab1:
# Basic information inputs
title = st.text_input("Video Title",
placeholder="Enter your video title")
description = st.text_area("Video Description",
placeholder="Enter your video description")
col1, col2 = st.columns(2)
with col1:
num_tags = st.number_input("Number of Tags",
min_value=5,
max_value=30,
value=15)
with col2:
include_trending = st.checkbox("Include Trending Suggestions", value=True)
if st.button("Generate Tags"):
if not title:
st.error("Please enter a video title.")
return
with st.spinner("Generating tags..."):
# Generate tags using the comprehensive method
tags = generate_tags_from_title_description(title, description, num_tags)
if tags:
# Analyze tags
st.session_state.tag_analysis = analyze_tags(tags)
st.session_state.generated_tags = tags
# Display tags in the new format
st.subheader("Generated Tags")
display_tags(tags)
# Add copy button for all tags
tags_text = ", ".join(tags)
st.text_area("Tags (copy to use)", value=tags_text, height=100)
# Display character count
char_count = len(tags_text)
st.info(f"Total characters: {char_count}/500 ({500 - char_count} remaining)")
# Quick analysis summary
col1, col2, col3 = st.columns(3)
with col1:
st.metric("Number of Tags", len(tags))
with col2:
st.metric("Optimization Score", f"{st.session_state.tag_analysis['optimization_score']}%")
with col3:
st.metric("Avg Tag Length", f"{st.session_state.tag_analysis['avg_tag_length']:.1f}")
# Display trending data summary if enabled
if include_trending:
st.subheader("Trending Data Used")
trends = get_comprehensive_trends(title, description)
# Create columns for different trend types
tcol1, tcol2, tcol3 = st.columns(3)
with tcol1:
st.markdown("##### Related Topics")
if trends['topics']:
for topic in trends['topics'][:5]:
st.markdown(f"{topic}")
else:
st.markdown("*No related topics found*")
with tcol2:
st.markdown("##### Related Queries")
if trends['queries']:
for query in trends['queries'][:5]:
st.markdown(f"{query}")
else:
st.markdown("*No related queries found*")
with tcol3:
st.markdown("##### Trending Suggestions")
if trends['trending']:
for trend in trends['trending'][:5]:
st.markdown(f"{trend}")
else:
st.markdown("*No trending suggestions found*")
else:
st.error("Failed to generate tags. Please try again.")
with tab2:
st.info("Advanced tag generation options coming soon!")
st.markdown("""
Future features will include:
- Competitor tag analysis
- Tag performance tracking
- Category-specific tag suggestions
- Multi-language tag generation
- Tag sets management
""")
with tab3:
if st.session_state.tag_analysis:
st.subheader("Tag Analysis")
# Create metrics
col1, col2 = st.columns(2)
with col1:
st.metric("Total Tags", st.session_state.tag_analysis['total_tags'])
st.metric("Total Characters", st.session_state.tag_analysis['total_characters'])
st.metric("Average Tag Length", f"{st.session_state.tag_analysis['avg_tag_length']:.1f}")
with col2:
st.metric("Duplicate Tags", st.session_state.tag_analysis['duplicate_tags'])
st.metric("Single Word Tags", len(st.session_state.tag_analysis['single_word_tags']))
st.metric("Tags Too Long", len(st.session_state.tag_analysis['tags_too_long']))
# Optimization score with color
score = st.session_state.tag_analysis['optimization_score']
score_color = 'red' if score < 50 else 'orange' if score < 80 else 'green'
st.markdown(f"""
<div style='background-color: {score_color}; padding: 10px; border-radius: 5px; margin: 10px 0;'>
<h3 style='color: white; margin: 0;'>Optimization Score: {score}%</h3>
</div>
""", unsafe_allow_html=True)
# Optimization suggestions
st.subheader("Optimization Suggestions")
suggestions = []
if st.session_state.tag_analysis['total_tags'] < 5:
suggestions.append("❌ Add more tags (aim for at least 15)")
if st.session_state.tag_analysis['total_characters'] > 500:
suggestions.append("❌ Total character count exceeds limit (max 500)")
if st.session_state.tag_analysis['duplicate_tags'] > 0:
suggestions.append("❌ Remove duplicate tags")
if len(st.session_state.tag_analysis['tags_too_long']) > 0:
suggestions.append("❌ Some tags are too long (max 30 characters)")
if len(st.session_state.tag_analysis['single_word_tags']) > st.session_state.tag_analysis['total_tags'] * 0.5:
suggestions.append("❌ Too many single-word tags (use more specific phrases)")
if not suggestions:
st.success("✅ Your tags are well-optimized!")
else:
for suggestion in suggestions:
st.warning(suggestion)
else:
st.info("Generate tags first to see analysis")

View File

@@ -14,6 +14,9 @@ from .modules.description_generator import write_yt_description
from .modules.script_generator import write_yt_script
from .modules.thumbnail_generator import write_yt_thumbnail
from .modules.end_screen_generator import write_yt_end_screen
from .modules.tags_generator import write_yt_tags
from .modules.shorts_script_generator import write_yt_shorts
from .modules.community_post_generator import write_yt_community_post
def youtube_main_menu():
@@ -53,6 +56,15 @@ def youtube_main_menu():
"function": write_yt_script,
"status": "active"
},
{
"name": "YT Shorts Script Generator",
"icon": "📱",
"description": "Create engaging scripts optimized for YouTube Shorts format with vertical framing and hooks.",
"color": "#FF0000", # YouTube red
"category": "Content Creation",
"function": write_yt_shorts,
"status": "active"
},
# Optimization Tools
{
@@ -65,16 +77,16 @@ def youtube_main_menu():
"status": "active"
},
{
"name": "Tags Generator",
"name": "YouTube Tags Generator",
"icon": "🏷️",
"description": "Generate optimized tags for your videos with trending tag suggestions to improve discoverability.",
"color": "#CC0000", # Darker red for coming soon
"color": "#FF0000", # YouTube red
"category": "Optimization",
"function": None,
"status": "coming_soon"
"function": write_yt_tags,
"status": "active"
},
# Engagement Tools (Coming Soon)
# Engagement Tools
{
"name": "End Screen Generator",
"icon": "🎬",
@@ -84,6 +96,15 @@ def youtube_main_menu():
"function": write_yt_end_screen,
"status": "active"
},
{
"name": "Community Post Generator",
"icon": "💬",
"description": "Generate engaging community posts with AI-powered content suggestions and timing optimization.",
"color": "#FF0000", # YouTube red
"category": "Engagement",
"function": write_yt_community_post,
"status": "active"
},
{
"name": "Playlist Description Generator",
"icon": "📚",
@@ -94,7 +115,7 @@ def youtube_main_menu():
"status": "coming_soon"
},
# Future Tools (Coming Soon)
# Future Tools
{
"name": "Analytics Insights",
"icon": "📊",
@@ -121,24 +142,6 @@ def youtube_main_menu():
"category": "Future Tools",
"function": None,
"status": "future"
},
{
"name": "Shorts Script Generator",
"icon": "📱",
"description": "Create engaging scripts optimized for YouTube Shorts format.",
"color": "#990000", # Even darker red for future
"category": "Future Tools",
"function": None,
"status": "future"
},
{
"name": "Community Post Generator",
"icon": "💬",
"description": "Generate engaging community posts to keep your audience active between videos.",
"color": "#990000", # Even darker red for future
"category": "Future Tools",
"function": None,
"status": "future"
}
]
@@ -175,27 +178,12 @@ def youtube_main_menu():
# Display the dashboard
# Header
st.markdown("""
<div style='background-color: #f0f2f6; padding: 20px; border-radius: 10px; margin-bottom: 20px;'>
<div style='background-color: #f0f2f6; padding: 10px; border-radius: 5px; margin-bottom: 10px;'>
<h1 style='color: #FF0000; text-align: center;'>🎥 YouTube AI Writer</h1>
<p style='text-align: center;'>Generate professional YouTube content with AI-powered tools</p>
<p style='text-align: center;'>Generate professional YouTube content with ALwrity's AI-powered tools</p>
</div>
""", unsafe_allow_html=True)
# Introduction
st.markdown("""
## Welcome to the YouTube AI Writer Suite
This dashboard provides access to a variety of tools for creating and optimizing YouTube content.
Select a tool below to get started with generating professional content for your channel.
### How to Use This Dashboard
1. Browse the available tools below
2. Click on a tool card to access its specific functionality
3. Fill in the required information
4. Generate high-quality content for your YouTube channel
""")
# Group tools by category
categories = {}
for tool in youtube_tools:

View File

@@ -5,6 +5,12 @@ from lib.utils.content_generators import content_planning_tools, ai_writers
from lib.utils.alwrity_utils import ai_social_writer
from lib.utils.seo_tools import ai_seo_tools
from lib.utils.settings_page import render_settings_page
# Import social media writer functions
from lib.ai_writers.facebook_ai_writer import facebook_post_writer
from lib.ai_writers.linkedin_ai_writer import linked_post_writer
from lib.ai_writers.twitter_ai_writer import tweet_writer
from lib.ai_writers.insta_ai_writer import insta_writer
from lib.ai_writers.youtube_writers.youtube_ai_writer import youtube_main_menu
def setup_ui():
@@ -17,10 +23,41 @@ def setup_ui():
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
}
/* Compact layout styling with zero top padding when sub-tab selected */
.main .block-container {
padding-top: 0 !important; /* Remove all top padding */
padding-bottom: 0;
max-width: 100%;
}
/* Remove extra padding and margins */
.stMarkdown {
margin: 0;
padding: 0;
}
/* Header styling with zero margins when in sub-tab */
.sub-tab-active h1, .sub-tab-active h2, .sub-tab-active h3 {
display: none; /* Hide headers in sub-tab mode */
}
/* Remove extra padding in containers */
.stMarkdown {
margin-bottom: 0;
}
/* Header styling */
h1, h2, h3 {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-weight: 600;
margin-top: 0;
margin-bottom: 0.5rem; /* Reduced from 1rem */
padding-top: 0;
}
/* Reduce spacing between elements */
.element-container {
margin-bottom: 0.5rem; /* Reduced from 1rem */
}
/* Button styling */
@@ -28,6 +65,7 @@ def setup_ui():
border-radius: 8px;
font-weight: 500;
transition: all 0.3s ease;
margin-bottom: 0.25rem; /* Reduced from 0.5rem */
}
.stButton > button:hover {
@@ -51,27 +89,36 @@ def setup_ui():
.streamlit-expanderHeader {
font-weight: 500;
color: #2c3e50;
margin-bottom: 0.5rem;
}
/* Success message styling */
.stSuccess {
background: linear-gradient(135deg, #43c6ac 0%, #191654 100%);
padding: 1rem;
padding: 0.75rem;
border-radius: 8px;
color: white;
margin-bottom: 1rem;
}
/* Error message styling */
.stError {
background: linear-gradient(135deg, #ff6b6b 0%, #ff8e8e 100%);
padding: 1rem;
padding: 0.75rem;
border-radius: 8px;
color: white;
margin-bottom: 1rem;
}
/* Info message styling */
.stInfo {
padding: 0.75rem;
margin-bottom: 1rem;
}
/* Sidebar navigation styling */
.sidebar-nav {
padding: 1rem 0;
padding: 0.5rem 0;
}
.nav-button {
@@ -90,13 +137,157 @@ def setup_ui():
.nav-button:hover {
background: rgba(0,0,0,0.05);
padding-left: 1.5rem;
padding-left: 0.5rem;
}
.nav-button.active {
background: #1565C0;
color: white;
}
/* Enhanced Sub-menu styling with minimal spacing */
.sub-menu {
padding-left: 1rem;
margin: 0;
border-left: 2px solid rgba(21, 101, 192, 0.3);
background: rgba(255, 255, 255, 0.05);
border-radius: 0 8px 8px 0;
padding-top: 0;
padding-bottom: 0;
}
/* Sub-menu button styling with minimal gaps */
.sub-menu .stButton > button {
font-size: 0.9rem;
text-align: left;
padding: 0.4rem 0.8rem;
background: transparent;
border: none;
color: #2c3e50;
font-weight: 500;
transition: all 0.2s ease;
margin: 0;
border-radius: 4px;
min-height: 0;
height: auto;
line-height: 1.2;
width: 100%;
}
/* Platform-specific button styles */
.facebook-button .stButton > button {
color: #4267B2;
background: rgba(66, 103, 178, 0.1);
}
.linkedin-button .stButton > button {
color: #0077B5;
background: rgba(0, 119, 181, 0.1);
}
.twitter-button .stButton > button {
color: #1DA1F2;
background: rgba(29, 161, 242, 0.1);
}
.instagram-button .stButton > button {
color: #E1306C;
background: rgba(225, 48, 108, 0.1);
}
.youtube-button .stButton > button {
color: #FF0000;
background: rgba(255, 0, 0, 0.1);
}
/* Platform-specific hover states */
.facebook-button .stButton > button:hover {
background: rgba(66, 103, 178, 0.2) !important;
color: #4267B2 !important;
}
.linkedin-button .stButton > button:hover {
background: rgba(0, 119, 181, 0.2) !important;
color: #0077B5 !important;
}
.twitter-button .stButton > button:hover {
background: rgba(29, 161, 242, 0.2) !important;
color: #1DA1F2 !important;
}
.instagram-button .stButton > button:hover {
background: rgba(225, 48, 108, 0.2) !important;
color: #E1306C !important;
}
.youtube-button .stButton > button:hover {
background: rgba(255, 0, 0, 0.2) !important;
color: #FF0000 !important;
}
/* Platform-specific active states */
.facebook-button.active .stButton > button {
background: #4267B2 !important;
color: white !important;
}
.linkedin-button.active .stButton > button {
background: #0077B5 !important;
color: white !important;
}
.twitter-button.active .stButton > button {
background: #1DA1F2 !important;
color: white !important;
}
.instagram-button.active .stButton > button {
background: #E1306C !important;
color: white !important;
}
.youtube-button.active .stButton > button {
background: #FF0000 !important;
color: white !important;
}
/* Remove any extra spacing from button containers */
.sub-menu .stButton {
margin: 0;
padding: 0;
}
.sub-menu > div {
margin: 0;
padding: 0;
}
.sub-menu .element-container {
margin: 0;
padding: 0;
}
/* Ensure minimal gaps between elements */
.sub-menu > div:not(:last-child) {
margin-bottom: 1px;
}
/* Sidebar icon styling */
.sidebar-icon {
padding: 1rem;
text-align: center;
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
}
.sidebar-icon img {
width: 80px !important;
height: auto !important;
margin: 0 auto;
}
</style>
""", unsafe_allow_html=True)
@@ -106,6 +297,10 @@ def setup_alwrity_ui():
# Initialize session state for active tab if not exists
if 'active_tab' not in st.session_state:
st.session_state.active_tab = "Content Planning"
# Initialize session state for active sub-tab if not exists
if 'active_sub_tab' not in st.session_state:
st.session_state.active_sub_tab = None
# Define the navigation items with their icons and functions
nav_items = {
@@ -113,7 +308,7 @@ def setup_alwrity_ui():
"AI Writers": ("📝", ai_writers),
"Agents Teams": ("🤝", lambda: st.subheader("Agents Teams - Coming Soon!")),
"AI SEO Tools": ("🔍", ai_seo_tools),
"AI Social Tools": ("📱", ai_social_writer),
"AI Social Tools": ("📱", None), # Set to None as we'll handle this separately
"Ask Alwrity": ("💬", lambda: (
st.subheader("Chat with your Data, Chat with any Data.. COMING SOON !"),
st.markdown("Create a collection by uploading files (PDF, MD, CSV, etc), or crawl a data source (Websites, more sources coming soon."),
@@ -121,6 +316,15 @@ def setup_alwrity_ui():
)),
"ALwrity Settings": ("⚙️", render_settings_page)
}
# Define sub-menu items for AI Social Tools
social_tools_submenu = {
"Facebook": ("📘", lambda: facebook_post_writer()),
"LinkedIn": ("💼", lambda: linked_post_writer()),
"Twitter": ("🐦", lambda: tweet_writer()),
"Instagram": ("📸", lambda: insta_writer()),
"YouTube": ("🎥", lambda: youtube_main_menu())
}
# Create sidebar navigation
st.sidebar.markdown("### ALwrity Options")
@@ -129,12 +333,106 @@ def setup_alwrity_ui():
# Create navigation buttons
for name, (icon, func) in nav_items.items():
button_class = "nav-button active" if st.session_state.active_tab == name else "nav-button"
if st.sidebar.button(f"{icon} {name}", key=f"nav_{name}",
help=f"Navigate to {name}", use_container_width=True):
st.session_state.active_tab = name
if name == "AI Social Tools":
# For AI Social Tools, we'll create a button that toggles the sub-menu
if st.sidebar.button(f"{icon} {name}", key=f"nav_{name}",
help=f"Navigate to {name}", use_container_width=True):
st.session_state.active_tab = name
# Reset sub-tab when main tab changes
st.session_state.active_sub_tab = None
# If AI Social Tools is active, show the sub-menu
if st.session_state.active_tab == "AI Social Tools":
st.sidebar.markdown('<div class="sub-menu">', unsafe_allow_html=True)
# Create sub-menu buttons
for sub_name, (sub_icon, sub_func) in social_tools_submenu.items():
# Create the button with a custom key that includes the platform name
button_key = f"sub_{sub_name}"
# Determine if this button is active
is_active = st.session_state.active_sub_tab == sub_name
# Create a container with the platform-specific class
platform_class = f"{sub_name.lower()}-button"
if is_active:
platform_class += " active"
# Add the platform-specific class to the button container
st.sidebar.markdown(f'<div class="{platform_class}">', unsafe_allow_html=True)
# Create the button
if st.sidebar.button(f"{sub_icon} {sub_name}", key=button_key,
help=f"Navigate to {sub_name}", use_container_width=True):
st.session_state.active_sub_tab = sub_name
# Close the div
st.sidebar.markdown('</div>', unsafe_allow_html=True)
st.sidebar.markdown('</div>', unsafe_allow_html=True)
else:
# For other navigation items, create regular buttons
if st.sidebar.button(f"{icon} {name}", key=f"nav_{name}",
help=f"Navigate to {name}", use_container_width=True):
st.session_state.active_tab = name
# Reset sub-tab when main tab changes
st.session_state.active_sub_tab = None
st.sidebar.markdown('</div>', unsafe_allow_html=True)
# Add the AskAlwrity icon at the bottom of sidebar
st.sidebar.markdown('<div class="sidebar-icon">', unsafe_allow_html=True)
icon_path = os.path.join("lib", "workspace", "AskAlwrity-min.ico")
if os.path.exists(icon_path):
st.sidebar.image(icon_path, use_container_width=False)
st.sidebar.markdown('</div>', unsafe_allow_html=True)
# Display content based on active tab
st.title(f"{nav_items[st.session_state.active_tab][0]} {st.session_state.active_tab}")
nav_items[st.session_state.active_tab][1]()
if st.session_state.active_tab == "AI Social Tools":
if not st.session_state.active_sub_tab:
# Only show title and info when no sub-tab is selected
st.markdown("""
<style>
.main .block-container {
padding-top: 0.25rem !important;
}
</style>
""", unsafe_allow_html=True)
st.title(f"{nav_items[st.session_state.active_tab][0]} {st.session_state.active_tab}")
st.info("Please select a social media platform from the sidebar.")
else:
# When a platform is selected, show no title and minimize spacing
st.markdown("""
<style>
.main .block-container {
padding-top: 0 !important;
padding-bottom: 0;
}
/* Remove all margins and padding from content area */
.element-container {
margin: 0 !important;
padding: 0 !important;
}
/* Hide any automatic headers */
.main .block-container > div:first-child {
margin-top: 0 !important;
padding-top: 0 !important;
}
</style>
""", unsafe_allow_html=True)
# Call the function directly without any title
social_tools_submenu[st.session_state.active_sub_tab][1]()
else:
st.markdown("""
<style>
.main .block-container {
padding-top: 0.25rem !important;
padding-bottom: 0;
}
</style>
""", unsafe_allow_html=True)
st.title(f"{nav_items[st.session_state.active_tab][0]} {st.session_state.active_tab}")
nav_items[st.session_state.active_tab][1]()

View File

@@ -15,6 +15,7 @@ exa_py>=1.9.1
GoogleNews>=1.6.15
langchain-google-genai>=2.0.10
clint>=0.5.1
textblob==0.19.0
numpy>=1.22.4,<2.0.0
pandas>=2.0.3
scikit-learn>=1.3.2