AI writers, SEO, Social media, Settings, Dashboard UI styling changes

This commit is contained in:
ajaysi
2025-06-03 09:14:47 +05:30
parent 5ca2fd5977
commit fad9647b46
13 changed files with 2281 additions and 2091 deletions

View File

@@ -1,248 +0,0 @@
# Enhanced ALwrity Chatbot - Integration Summary
## 🎉 Integration Complete!
The Enhanced ALwrity Chatbot has been successfully integrated into the ALwrity application, providing a comprehensive conversational interface for all content creation needs.
## 📁 Files Created/Modified
### New Files Created
1. **`lib/chatbot_custom/enhanced_alwrity_chatbot.py`** - Main chatbot implementation
2. **`ENHANCED_CHATBOT_README.md`** - Comprehensive documentation
3. **`CHATBOT_INTEGRATION_SUMMARY.md`** - This integration summary
### Files Modified
1. **`lib/utils/ui_setup.py`** - Updated navigation to include chatbot
- Added import for enhanced chatbot
- Replaced placeholder "Ask Alwrity(TBD)" with "ALwrity Assistant"
- Integrated chatbot function into navigation
## 🚀 Key Features Implemented
### 🤖 Core Chatbot Functionality
- **Conversational Interface**: Natural language interaction with AI
- **Intent Recognition**: Smart understanding of user requests
- **Context Awareness**: Maintains conversation history and context
- **Session Management**: Persistent chat sessions with save/load capability
### 🛠️ Tool Integration
- **All AI Writers**: Direct access to 11+ writing tools
- **SEO Tools**: Competitor analysis, content gap analysis, keyword research
- **Content Planning**: Calendar creation, repurposing, strategy development
- **Social Media**: Multi-platform content creation and optimization
### 📄 Document & URL Analysis
- **File Upload**: Support for PDF, TXT, DOCX, CSV, XLSX, images
- **URL Analysis**: Comprehensive website analysis and insights
- **Content Analysis**: AI-powered content evaluation and recommendations
- **Real-time Processing**: Instant analysis and feedback
### 🎯 Smart Suggestions
- **Tool Recommendations**: Context-aware feature suggestions
- **Template Library**: Pre-built templates for common content types
- **Quick Actions**: One-click access to popular features
- **Guided Workflows**: Step-by-step assistance for complex tasks
## 🎨 User Interface Features
### 📱 Modern Chat Interface
- **Clean Design**: Professional, user-friendly interface
- **Avatar System**: Visual distinction between user and AI messages
- **Rich Formatting**: Markdown support for formatted responses
- **Responsive Layout**: Optimized for different screen sizes
### 🔧 Sidebar Navigation
- **Tool Categories**: Organized access to all features
- 📝 AI Writers
- 🔍 SEO Tools
- 📅 Content Planning
- 📋 Quick Templates
- 💬 Chat History
- **Expandable Sections**: Collapsible tool groups for better organization
- **Quick Access**: Direct tool launching from sidebar
### ⚡ Quick Actions
- **📝 Write Blog Post**: Instant blog creation assistance
- **📱 Social Media Post**: Platform-specific content creation
- **🔍 SEO Analysis**: Website and content optimization
- **📊 Content Ideas**: Brainstorm content topics and strategies
## 🔗 Integration Points
### 🎯 AI Writers Integration
```python
# Direct access to all AI writers
self.ai_writers = list_ai_writers()
self.writer_functions = {
writer['name']: writer['function'] for writer in self.ai_writers
}
```
### 🔍 SEO Tools Integration
```python
# Content gap analysis integration
from ..ai_seo_tools.content_gap_analysis.main import ContentGapAnalysis
analyzer = ContentGapAnalysis()
analysis = analyzer.website_analyzer.analyze_website(url)
```
### 📊 Content Planning Integration
```python
# Content repurposing integration
from ..ai_seo_tools.content_calendar.ui.components.content_repurposing_ui import ContentRepurposingUI
```
## 🧠 AI Capabilities
### 🎯 Intent Recognition System
```python
intent_keywords = {
"write": ["write", "create", "generate", "compose", "draft"],
"analyze": ["analyze", "review", "check", "examine", "evaluate"],
"seo": ["seo", "optimize", "rank", "keyword", "search"],
"social": ["social", "facebook", "twitter", "linkedin", "instagram"],
"blog": ["blog", "article", "post", "content"],
"help": ["help", "how", "what", "explain", "guide"],
"research": ["research", "competitor", "market", "trend"],
"plan": ["plan", "strategy", "calendar", "schedule"]
}
```
### 🤖 Contextual Response Generation
- **System Prompts**: Tailored prompts based on user intent
- **Context Building**: Conversation history integration
- **Smart Suggestions**: Relevant tool recommendations
- **Error Handling**: Graceful error management and recovery
## 📈 Usage Examples
### Content Creation Workflow
```
User: "I need to write a blog post about sustainable marketing"
Assistant: Provides guidance, suggests AI Blog Writer, offers templates
User: "Create it for business owners, 1000 words"
Assistant: Generates comprehensive blog post with SEO optimization
```
### SEO Analysis Workflow
```
User: "Analyze my website for SEO opportunities"
Assistant: Requests URL, performs comprehensive analysis
User: Provides website URL
Assistant: Returns detailed SEO audit with actionable recommendations
```
### Content Planning Workflow
```
User: "Help me plan a content calendar for next month"
Assistant: Guides through calendar creation process
User: Provides business details and goals
Assistant: Creates strategic content calendar with platform-specific content
```
## 🎯 Benefits Delivered
### For Content Creators
- **Unified Interface**: All tools accessible through conversation
- **Intelligent Guidance**: AI-powered content creation assistance
- **Time Savings**: Streamlined workflow and automation
- **Quality Improvement**: Professional-grade content generation
### For Businesses
- **Scalable Content**: Efficient content production at scale
- **Brand Consistency**: Maintained voice across all platforms
- **Strategic Planning**: Data-driven content strategies
- **Competitive Intelligence**: Advanced competitor analysis
### For SEO Professionals
- **Comprehensive Toolkit**: All SEO tools in one interface
- **Automated Analysis**: AI-powered SEO insights
- **Content Optimization**: Search engine friendly content
- **Performance Tracking**: Detailed analytics and reporting
## 🔧 Technical Implementation
### Architecture
- **Modular Design**: Clean separation of concerns
- **Error Handling**: Robust error management
- **Session State**: Persistent conversation management
- **File Processing**: Secure file upload and analysis
### Performance
- **Efficient Processing**: Optimized AI model interactions
- **Caching**: Smart caching for improved response times
- **Background Processing**: Non-blocking operations
- **Resource Management**: Efficient memory and CPU usage
## 🚀 Access Instructions
### Launch the Chatbot
1. **Start ALwrity**: Run `streamlit run alwrity.py`
2. **Navigate**: Click "🤖 ALwrity Assistant" in the sidebar
3. **Start Chatting**: Begin your content creation journey!
### First Steps
1. **Welcome Message**: Read the capability overview
2. **Try Quick Actions**: Use the quick action buttons
3. **Upload Files**: Test document analysis features
4. **Explore Tools**: Use sidebar to discover all features
## 🎉 Success Metrics
### Implementation Success
-**Complete Integration**: All existing tools accessible
-**Seamless Navigation**: Smooth user experience
-**Error Handling**: Robust error management
-**Documentation**: Comprehensive user guides
### Feature Completeness
-**11+ AI Writers**: All writing tools integrated
-**SEO Tools**: Complete SEO toolkit access
-**Content Planning**: Full planning capabilities
-**File Analysis**: Multi-format file support
-**URL Analysis**: Website analysis capabilities
### User Experience
-**Intuitive Interface**: Easy-to-use chat interface
-**Smart Suggestions**: Context-aware recommendations
-**Quick Actions**: One-click common tasks
-**Help System**: Comprehensive guidance
## 🔮 Future Enhancements
### Planned Features
- **Voice Interface**: Speech-to-text and text-to-speech
- **Visual Content**: AI-powered image and video generation
- **Advanced Analytics**: Deeper performance insights
- **Team Collaboration**: Shared workspaces and collaboration
- **API Integration**: External platform connections
### Upcoming Integrations
- **Social Media APIs**: Direct publishing capabilities
- **CMS Platforms**: WordPress, Shopify integration
- **Analytics Tools**: Google Analytics, social insights
- **Design Software**: Canva, Adobe Creative Suite
## 📞 Support & Resources
### Documentation
- **`ENHANCED_CHATBOT_README.md`**: Comprehensive user guide
- **Inline Help**: Contextual assistance within the app
- **Quick Start**: Step-by-step getting started guide
### Technical Support
- **Error Handling**: Built-in error management
- **Logging**: Comprehensive logging for troubleshooting
- **Recovery**: Automatic error recovery mechanisms
## 🎊 Conclusion
The Enhanced ALwrity Chatbot successfully transforms the ALwrity platform from a collection of individual tools into a unified, intelligent content creation assistant. Users can now access all features through natural conversation, making content creation more intuitive, efficient, and enjoyable.
**Key Achievements:**
- 🎯 **Unified Experience**: Single interface for all content needs
- 🤖 **AI Intelligence**: Smart assistance and recommendations
- 🚀 **Enhanced Productivity**: Streamlined workflows and automation
- 📈 **Better Results**: Higher quality content and better performance
**Ready to revolutionize your content creation?** The Enhanced ALwrity Chatbot is now live and ready to assist with all your content creation needs!

View File

@@ -1,174 +0,0 @@
# 🔄 Smart Content Repurposing Engine - Integration Summary
## ✅ Integration Complete!
The **Smart Content Repurposing Engine** has been successfully integrated into your ALwrity application. This powerful AI-driven feature transforms single pieces of content into multiple platform-optimized variations, maximizing your content's reach and impact.
## 🎯 What's Been Integrated
### 1. Core Engine Components
- **Content Atomizer**: Extracts key content elements (statistics, quotes, tips, examples)
- **Content Repurposer**: Creates platform-specific content variations
- **Content Series Repurposer**: Generates cross-platform content series
- **Smart Repurposing Engine**: Orchestrates the entire repurposing workflow
### 2. User Interface Integration
- **New Tab in Content Calendar**: "🔄 Smart Repurposing" tab added to the Content Calendar Dashboard
- **Comprehensive UI**: Four main sections:
- Single Content Repurposing
- Content Series Creation
- Content Analysis
- Repurposing Dashboard with metrics
### 3. Platform Support
The engine supports repurposing for:
- **Twitter**: 280 characters, engaging tone, hashtags
- **LinkedIn**: 3000 characters, professional tone, business focus
- **Instagram**: 2200 characters, visual-focused, casual tone
- **Facebook**: Unlimited characters, conversational tone
- **Website**: Long-form, comprehensive content
## 🚀 How to Access the Feature
1. **Start ALwrity**: Run `streamlit run alwrity.py`
2. **Navigate to Content Planning**: Click "📅 Content Planning" in the sidebar
3. **Access Smart Repurposing**: Click the "🔄 Smart Repurposing" tab in the Content Calendar Dashboard
## 🔧 Key Features Available
### Single Content Repurposing
- Input content manually, upload files, or select from calendar
- Choose target platforms (Twitter, LinkedIn, Instagram, etc.)
- Select repurposing strategies (Adaptive, Atomic, Series-based)
- Generate platform-optimized content instantly
### Content Series Creation
- Create progressive disclosure series across platforms
- Generate platform-native content series
- Timeline preview and scheduling
- Cross-platform content coordination
### Content Analysis
- AI-powered content atomization
- Repurposing potential assessment
- Platform recommendations
- Content richness analysis
### Repurposing Dashboard
- Performance metrics and insights
- Content multiplication statistics
- Time savings calculations
- Platform distribution analytics
## 📁 File Structure
```
lib/ai_seo_tools/content_calendar/
├── core/
│ ├── content_generator.py # Enhanced with repurposing integration
│ └── content_repurposer.py # Main repurposing engine
├── ui/
│ ├── dashboard.py # Updated with Smart Repurposing tab
│ └── components/
│ └── content_repurposing_ui.py # Complete UI component
└── ...
```
## 🎮 Demo and Testing
### Run the Demo
```bash
python demo_smart_repurposing.py
```
This demonstrates:
- Content atomization and analysis
- Platform-specific repurposing
- Cross-platform series creation
- AI-powered recommendations
- Comprehensive workflow
### Test Results
✅ Content atomization working
✅ Platform-specific repurposing working
✅ Content series creation working
✅ UI integration successful
✅ Error handling implemented
## 🔧 Technical Implementation
### AI Integration
- Uses existing `llm_text_gen` function for consistency
- Structured JSON responses for content atomization
- Platform-specific prompts for optimal content generation
- Error handling and fallback mechanisms
### Database Integration
- Seamless integration with existing `ContentItem` model
- Automatic tagging and metadata management
- Content relationship tracking
- Status and scheduling management
### Error Handling
- Graceful degradation when AI services are unavailable
- Fallback content extraction methods
- User-friendly error messages
- Comprehensive logging
## 🎯 Benefits Delivered
### Content Multiplication
- **10x Content Output**: Transform 1 piece into 10+ variations
- **Platform Optimization**: Each piece tailored for specific platforms
- **Time Savings**: 20+ hours saved per content piece
- **Consistency**: Maintain brand voice across platforms
### Workflow Enhancement
- **Integrated Experience**: Works within existing Content Calendar
- **AI-Powered Intelligence**: Smart recommendations and analysis
- **Batch Processing**: Handle multiple pieces simultaneously
- **Performance Tracking**: Monitor repurposing effectiveness
## 🔮 Future Enhancements
### Planned Features
- **Visual Content Generation**: AI-powered image and video creation
- **Advanced Analytics**: Detailed performance tracking
- **Content Templates**: Pre-built repurposing templates
- **Automation Rules**: Automatic repurposing based on triggers
- **Multi-language Support**: Content translation and localization
### Integration Opportunities
- **Social Media APIs**: Direct publishing to platforms
- **Content Management Systems**: CMS integration
- **Analytics Platforms**: Performance data integration
- **Team Collaboration**: Multi-user workflow support
## 📚 Documentation
- **Main Documentation**: `SMART_REPURPOSING_README.md`
- **Demo Script**: `demo_smart_repurposing.py`
- **Integration Summary**: This file
- **Code Comments**: Comprehensive inline documentation
## 🎉 Success Metrics
The integration has successfully delivered:
1. **✅ Seamless Integration**: No disruption to existing workflows
2. **✅ Enhanced Functionality**: Powerful new content capabilities
3. **✅ User-Friendly Interface**: Intuitive and accessible UI
4. **✅ Robust Performance**: Reliable operation with error handling
5. **✅ Scalable Architecture**: Ready for future enhancements
## 🚀 Ready to Use!
Your Smart Content Repurposing Engine is now live and ready to transform your content creation process. Start by:
1. Creating or selecting content in the Content Calendar
2. Navigating to the Smart Repurposing tab
3. Experimenting with different repurposing strategies
4. Analyzing the generated content variations
5. Publishing across multiple platforms
**Happy Content Creating! 🎯**

View File

@@ -1,221 +0,0 @@
{
"name": null,
"description": null,
"start_date": "2025-05-22T08:00:48.925689",
"duration": "monthly",
"platforms": [
"website",
"instagram",
"twitter",
"linkedin",
"facebook"
],
"schedule": {
"2025-05-22": [
{
"title": "AI writer",
"description": "",
"content_type": "blog_post",
"platforms": [
"website"
],
"publish_date": "2025-05-22T00:00:00",
"seo_data": {
"title": "AI writer",
"meta_description": "",
"keywords": [],
"structured_data": {},
"canonical_url": null,
"og_tags": null,
"twitter_cards": null
},
"status": "Draft",
"author": null,
"tags": [],
"notes": null
},
{
"title": "alwrity.",
"description": "",
"content_type": "blog_post",
"platforms": [
"linkedin"
],
"publish_date": "2025-05-22T00:00:00",
"seo_data": {
"title": "alwrity.",
"meta_description": "",
"keywords": [],
"structured_data": {},
"canonical_url": null,
"og_tags": null,
"twitter_cards": null
},
"status": "Draft",
"author": null,
"tags": [],
"notes": null
}
],
"2025-05-31": [
{
"title": "ai content generation",
"description": "",
"content_type": "blog_post",
"platforms": [
"website"
],
"publish_date": "2025-05-31T00:00:00",
"seo_data": {
"title": "ai content generation",
"meta_description": "",
"keywords": [],
"structured_data": {},
"canonical_url": null,
"og_tags": null,
"twitter_cards": null
},
"status": "Draft",
"author": null,
"tags": [],
"notes": null
},
{
"title": "Alwrity content generation with AI powered",
"description": "",
"content_type": "blog_post",
"platforms": [
"website"
],
"publish_date": "2025-05-31T00:00:00",
"seo_data": {
"title": "Alwrity content generation with AI powered",
"meta_description": "",
"keywords": [],
"structured_data": {},
"canonical_url": null,
"og_tags": null,
"twitter_cards": null
},
"status": "Draft",
"author": null,
"tags": [],
"notes": null
}
],
"2025-05-30": [
{
"title": "AI content",
"description": "",
"content_type": "blog_post",
"platforms": [
"website"
],
"publish_date": "2025-05-30T00:00:00",
"seo_data": {
"title": "AI content",
"meta_description": "",
"keywords": [],
"structured_data": {},
"canonical_url": null,
"og_tags": null,
"twitter_cards": null
},
"status": "Draft",
"author": null,
"tags": [],
"notes": null
},
{
"title": "Content scheduling",
"description": "",
"content_type": "blog_post",
"platforms": [
"website"
],
"publish_date": "2025-05-30T00:00:00",
"seo_data": {
"title": "Content scheduling",
"meta_description": "",
"keywords": [],
"structured_data": {},
"canonical_url": null,
"og_tags": null,
"twitter_cards": null
},
"status": "Draft",
"author": null,
"tags": [],
"notes": null
},
{
"title": "Ai content generation",
"description": "",
"content_type": "blog_post",
"platforms": [
"website"
],
"publish_date": "2025-05-30T00:00:00",
"seo_data": {
"title": "Ai content generation",
"meta_description": "",
"keywords": [],
"structured_data": {},
"canonical_url": null,
"og_tags": null,
"twitter_cards": null
},
"status": "Draft",
"author": null,
"tags": [],
"notes": null
},
{
"title": "https://alwrity.com",
"description": "",
"content_type": "blog_post",
"platforms": [
"website"
],
"publish_date": "2025-05-30T00:00:00",
"seo_data": {
"title": "https://alwrity.com",
"meta_description": "",
"keywords": [],
"structured_data": {},
"canonical_url": null,
"og_tags": null,
"twitter_cards": null
},
"status": "Draft",
"author": null,
"tags": [],
"notes": null
}
],
"2025-06-27": [
{
"title": "AI title generation",
"description": "",
"content_type": "blog_post",
"platforms": [
"website"
],
"publish_date": "2025-06-27T00:00:00",
"seo_data": {
"title": "AI title generation",
"meta_description": "",
"keywords": [],
"structured_data": {},
"canonical_url": null,
"og_tags": null,
"twitter_cards": null
},
"status": "Draft",
"author": null,
"tags": [],
"notes": null
}
]
}
}

View File

@@ -344,4 +344,4 @@ def main():
print("your content creation process!")
if __name__ == "__main__":
main()
main()

View File

@@ -9,6 +9,7 @@ from lib.ai_writers.blog_rewriter_updater.ai_blog_rewriter import write_blog_rew
from lib.ai_writers.ai_blog_faqs_writer.faqs_ui import main as faqs_generator
from lib.ai_writers.ai_blog_writer.ai_blog_generator import ai_blog_writer_page
from lib.ai_writers.ai_outline_writer.outline_ui import main as outline_generator
from lib.alwrity_ui.dashboard_styles import apply_dashboard_style, render_dashboard_header, render_category_header, render_card
from loguru import logger
def list_ai_writers():
@@ -105,195 +106,58 @@ def list_ai_writers():
]
def get_ai_writers():
"""Render the AI Writers dashboard UI with a professional, clickable card layout."""
logger.info("Initializing AI Writers Dashboard")
"""Main function to display AI writers dashboard with premium glassmorphic design."""
logger.info("Starting AI Writers Dashboard")
# Apply common dashboard styling
apply_dashboard_style()
# Render dashboard header
render_dashboard_header(
"🤖 AI Content Writers",
"Choose from our collection of specialized AI writers, each designed for specific content types and industries. Create engaging, high-quality content with just a few clicks."
)
writers = list_ai_writers()
logger.info(f"Found {len(writers)} AI writers")
# Add custom CSS for a professional dashboard with VIBRANT clickable cards
st.markdown("""
<style>
/* Base UI improvements */
body, .main .block-container {
background: linear-gradient(135deg, #f0f4f8 0%, #e6eef7 100%) !important;
min-height: 100vh;
color: #2c3e50;
font-family: 'Helvetica Neue', sans-serif;
}
/* Main layout improvements */
.main .block-container {
padding: 1.5rem 2rem 2rem 2rem !important;
max-width: 1200px;
margin: 0 auto;
}
# Group writers by category for better organization
categories = {}
for writer in writers:
category = writer["category"]
if category not in categories:
categories[category] = []
categories[category].append(writer)
/* Dashboard header */
.dashboard-header {
text-align: center;
margin-bottom: 2.5rem;
padding: 2rem 1.5rem;
background: linear-gradient(135deg, #ffffff 0%, #f5f7fa 100%);
border-radius: 16px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.07);
border: 1px solid rgba(0, 0, 0, 0.04);
}
.dashboard-header h1 {
font-size: 2.6em;
font-family: 'Helvetica Neue', sans-serif;
font-weight: 700;
color: #1976d2;
margin-bottom: 0.5rem;
}
.dashboard-header p {
font-size: 1.15em;
color: #546e7a;
max-width: 700px;
margin: 0 auto;
line-height: 1.6;
}
/* Styling st.button to look like a clickable card - PREMIUM VIBRANT */
[data-testid="stVerticalBlock"] [data-testid="stButton"] > button {
/* Vivid Gradient Background - More saturated blue-purple */
background: linear-gradient(135deg, #8a2be2 0%, #4169e1 100%);
color: #ffffff;
border: none;
padding: 1.8rem 1.5rem;
border-radius: 18px;
font-weight: 500;
font-size: 1rem;
font-family: 'Helvetica Neue', sans-serif;
transition: all 0.35s cubic-bezier(0.25, 0.8, 0.25, 1); /* Smoother, more premium transition */
box-shadow: 0 8px 20px rgba(77, 5, 232, 0.25), 0 2px 6px rgba(0, 0, 0, 0.15); /* Layered shadow for depth */
width: 100%;
height: 100%;
min-height: 190px;
margin-bottom: 0;
text-align: left;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
line-height: 1.5;
overflow: hidden;
transform: translateY(0); /* Starting position for hover animation */
position: relative; /* For pseudo-element effects */
}
/* Subtle shine effect on cards */
[data-testid="stVerticalBlock"] [data-testid="stButton"] > button::after {
content: '';
position: absolute;
top: 0;
left: -50%;
width: 150%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.1), transparent);
transform: skewX(-20deg);
transition: 0.5s;
opacity: 0;
}
/* Dynamic hover effects with gradient shift */
[data-testid="stVerticalBlock"] [data-testid="stButton"] > button:hover {
background: linear-gradient(135deg, #4169e1 0%, #8a2be2 100%); /* Reverse gradient on hover */
transform: translateY(-8px) scale(1.05); /* More dramatic lift */
box-shadow: 0 15px 30px rgba(77, 5, 232, 0.4), 0 5px 15px rgba(0, 0, 0, 0.2); /* Deeper shadow */
color: #ffffff;
}
/* Animate shine on hover */
[data-testid="stVerticalBlock"] [data-testid="stButton"] > button:hover::after {
left: 100%;
opacity: 1;
}
[data-testid="stVerticalBlock"] [data-testid="stButton"] > button:hover > div > p strong {
color: #ffffff; /* Bright white on hover */
text-shadow: 0 0 15px rgba(255,255,255,0.5); /* Glow effect on hover */
}
/* Target the paragraph generated by Streamlit inside the button */
[data-testid="stVerticalBlock"] [data-testid="stButton"] > button > div > p {
margin: 0;
line-height: 1.5;
color: rgba(255, 255, 255, 0.9); /* Slightly dimmed base text */
}
/* Icon (first line/element) - MORE PROMINENT */
[data-testid="stVerticalBlock"] [data-testid="stButton"] > button > div > p::first-line {
font-size: 2.3em; /* Larger icon */
line-height: 1.2;
display: block;
margin-bottom: 1rem;
color: #ffffff;
text-shadow: 0 0 10px rgba(255,255,255,0.4); /* Light glow effect */
}
/* Title (strong tag from markdown) - ENHANCED CONTRAST */
[data-testid="stVerticalBlock"] [data-testid="stButton"] > button > div > p strong {
font-size: 1.4em; /* Larger title */
font-weight: 700; /* Bolder */
color: #ffffff;
display: block;
margin: 0.7rem 0;
text-shadow: 1px 1px 4px rgba(0,0,0,0.3); /* Stronger shadow for better contrast */
letter-spacing: 0.5px; /* Slight letter spacing for premium feel */
}
/* Description - IMPROVED CONTRAST */
[data-testid="stVerticalBlock"] [data-testid="stButton"] > button > div > p {
font-size: 1rem; /* Slightly larger for readability */
color: rgba(255, 255, 255, 0.95); /* Better contrast */
text-shadow: 0 1px 2px rgba(0,0,0,0.1); /* Subtle shadow for text */
}
/* Column adjustments for consistent card height */
[data-testid="column"] {
display: flex;
flex-direction: column;
gap: 1.5rem; /* Consistent gap */
}
/* Hide Streamlit default title */
.stApp > header {
visibility: hidden;
}
</style>
""", unsafe_allow_html=True)
# Dashboard header
st.markdown("""
<div class="dashboard-header">
<h1>🚀 AI Content Creation Suite</h1>
<p>Welcome! Select the perfect AI writer tool from the options below to start creating amazing content.</p>
</div>
""", unsafe_allow_html=True)
# Create columns for the grid layout
cols = st.columns(3)
# Render buttons styled as cards for each writer
for idx, writer in enumerate(writers):
with cols[idx % 3]:
# Prepare the button label using simple Markdown with newlines
button_label = f"{writer['icon']}\n**{writer['name']}**\n{writer['description']}"
if st.button(
button_label,
key=f"writer_{writer['path']}",
help=f"Click to use the {writer['name']}", # More specific help text
use_container_width=True,
):
logger.info(f"Selected writer: {writer['name']} with path: {writer['path']}")
st.session_state.selected_writer = writer
st.query_params["writer"] = writer['path']
logger.info(f"Updated query params with writer: {writer['path']}")
st.rerun()
# Render writers by category with common cards
for category_name, category_writers in categories.items():
render_category_header(category_name)
# Create columns for this category
cols = st.columns(min(len(category_writers), 3))
for idx, writer in enumerate(category_writers):
with cols[idx % 3]:
# Use the common card renderer
if render_card(
icon=writer['icon'],
title=writer['name'],
description=writer['description'],
category=writer['category'],
key_suffix=f"{writer['path']}_{category_name}",
help_text=f"Launch {writer['name']} - {writer['description']}"
):
logger.info(f"Selected writer: {writer['name']} with path: {writer['path']}")
st.session_state.selected_writer = writer
st.query_params["writer"] = writer['path']
logger.info(f"Updated query params with writer: {writer['path']}")
st.rerun()
# Add spacing between categories
st.markdown('<div class="category-spacer"></div>', unsafe_allow_html=True)
logger.info("Finished rendering AI Writers Dashboard")
# Return writers list, though it's not strictly needed if only rendering UI
return writers
# Remove the old ai_writers function since it's now integrated into get_ai_writers

View File

@@ -0,0 +1,510 @@
import streamlit as st
def apply_dashboard_style():
"""Apply common glassmorphic styling for all dashboards (AI Writers, SEO Tools, Social Media)."""
st.markdown("""
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
/* Global styling with glassmorphic background */
.stApp {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
}
.main .block-container {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(20px);
border-radius: 24px;
border: 1px solid rgba(255, 255, 255, 0.1);
padding: 2rem 2.5rem 3rem 2.5rem !important;
max-width: 1400px;
margin: 2rem auto;
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.15);
}
/* Modern dashboard header with glassmorphic effect */
.dashboard-header {
text-align: center;
margin-bottom: 3rem;
padding: 3rem 2rem;
background: rgba(255, 255, 255, 0.08);
backdrop-filter: blur(15px);
border-radius: 20px;
border: 1px solid rgba(255, 255, 255, 0.15);
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1);
position: relative;
overflow: hidden;
}
.dashboard-header::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 2px;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.6), transparent);
animation: shimmer 3s ease-in-out infinite;
}
@keyframes shimmer {
0%, 100% { opacity: 0; }
50% { opacity: 1; }
}
.dashboard-header h1 {
font-size: 3.2em;
font-weight: 700;
color: #ffffff;
margin-bottom: 1rem;
text-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
letter-spacing: -0.02em;
line-height: 1.1;
}
.dashboard-header p {
font-size: 1.2em;
color: rgba(255, 255, 255, 0.85);
max-width: 600px;
margin: 0 auto;
line-height: 1.6;
font-weight: 400;
}
/* Category headers with modern styling */
.stMarkdown h2 {
color: #ffffff;
font-size: 1.8em;
font-weight: 600;
margin: 2.5rem 0 1.5rem 0;
padding-left: 1rem;
border-left: 4px solid rgba(255, 255, 255, 0.6);
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
letter-spacing: -0.01em;
}
/* Custom category headers */
.category-header {
margin: 3rem 0 2rem 0;
position: relative;
}
.category-header h2 {
color: #ffffff;
font-size: 1.8em;
font-weight: 600;
margin: 0 0 0.5rem 0;
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
letter-spacing: -0.01em;
}
.category-line {
height: 2px;
background: linear-gradient(90deg, rgba(255,255,255,0.6) 0%, rgba(255,255,255,0.2) 50%, transparent 100%);
border-radius: 1px;
margin-bottom: 1.5rem;
}
/* Cards container with grid layout */
.cards-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
gap: 1.5rem;
margin-bottom: 2rem;
}
/* Card container */
.card-container {
position: relative;
margin-bottom: 1.5rem;
}
/* Premium cards (works for both writer and tool cards) */
.premium-card {
background: rgba(255, 255, 255, 0.08);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.15);
border-radius: 20px;
padding: 0;
cursor: pointer;
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
position: relative;
overflow: hidden;
min-height: 200px;
box-shadow:
0 10px 30px rgba(0, 0, 0, 0.15),
inset 0 1px 0 rgba(255, 255, 255, 0.2);
transform: translateY(0) scale(1);
margin-bottom: 1rem;
}
/* Style all Streamlit buttons to match the glassmorphic design */
.card-container + div[data-testid="stButton"] > button,
.stButton > button {
background: rgba(255, 255, 255, 0.08) !important;
backdrop-filter: blur(20px) !important;
border: 1px solid rgba(255, 255, 255, 0.15) !important;
border-radius: 20px !important;
color: #ffffff !important;
font-family: 'Inter', sans-serif !important;
font-weight: 500 !important;
font-size: 1rem !important;
padding: 1rem 1.5rem !important;
min-height: 60px !important;
margin: 0 !important;
box-shadow:
0 8px 25px rgba(0, 0, 0, 0.15),
inset 0 1px 0 rgba(255, 255, 255, 0.2) !important;
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1) !important;
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3) !important;
position: relative !important;
overflow: hidden !important;
width: 100% !important;
}
/* Button hover effects */
.card-container + div[data-testid="stButton"] > button:hover,
.stButton > button:hover {
background: rgba(255, 255, 255, 0.12) !important;
backdrop-filter: blur(25px) !important;
transform: translateY(-4px) scale(1.02) !important;
box-shadow:
0 15px 35px rgba(0, 0, 0, 0.25),
0 0 0 1px rgba(255, 255, 255, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.3) !important;
border-color: rgba(255, 255, 255, 0.3) !important;
color: #ffffff !important;
}
/* Button focus state */
.card-container + div[data-testid="stButton"] > button:focus,
.stButton > button:focus {
outline: 2px solid rgba(255, 255, 255, 0.5) !important;
outline-offset: 2px !important;
background: rgba(255, 255, 255, 0.12) !important;
}
/* Button active state */
.card-container + div[data-testid="stButton"] > button:active,
.stButton > button:active {
transform: translateY(-2px) scale(1.01) !important;
transition: all 0.1s ease !important;
}
/* Add shine effect to buttons */
.card-container + div[data-testid="stButton"] > button::before,
.stButton > button::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.1), transparent);
transform: skewX(-20deg);
transition: left 0.6s ease;
pointer-events: none;
}
.card-container + div[data-testid="stButton"] > button:hover::before,
.stButton > button:hover::before {
left: 100%;
}
/* Card hover effects when hovering over the container */
.card-container:hover .premium-card {
background: rgba(255, 255, 255, 0.12);
backdrop-filter: blur(25px);
transform: translateY(-4px) scale(1.02);
box-shadow:
0 15px 35px rgba(0, 0, 0, 0.25),
0 0 0 1px rgba(255, 255, 255, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.3);
border-color: rgba(255, 255, 255, 0.3);
}
.card-container:hover .card-glow {
opacity: 1;
}
.card-container:hover .card-arrow {
transform: translateX(5px);
color: #ffffff;
}
.card-container:hover .card-shine {
left: 100%;
}
.card-container:hover .card-icon {
filter: drop-shadow(0 0 15px rgba(255, 255, 255, 0.5));
transform: scale(1.05);
}
.card-container:hover .card-category {
background: rgba(255, 255, 255, 0.2);
color: #ffffff;
}
/* Active/pressed state */
.card-container:active .premium-card {
transform: translateY(-2px) scale(1.01);
transition: all 0.1s ease;
}
/* Card glow effect */
.card-glow {
position: absolute;
top: -2px;
left: -2px;
right: -2px;
bottom: -2px;
background: linear-gradient(45deg, rgba(255,255,255,0.1), rgba(255,255,255,0.05));
border-radius: 22px;
opacity: 0;
transition: opacity 0.3s ease;
z-index: -1;
}
/* Card content wrapper */
.card-content {
padding: 2rem 1.8rem;
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
position: relative;
z-index: 2;
}
/* Card icon */
.card-icon {
font-size: 2.8em;
margin-bottom: 1rem;
color: #ffffff;
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
filter: drop-shadow(0 0 10px rgba(255, 255, 255, 0.3));
line-height: 1;
transition: all 0.3s ease;
}
/* Card title */
.card-title {
font-size: 1.3em;
font-weight: 600;
color: #ffffff;
margin-bottom: 0.8rem;
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
letter-spacing: -0.01em;
line-height: 1.3;
}
/* Card description */
.card-description {
font-size: 0.95em;
color: rgba(255, 255, 255, 0.85);
line-height: 1.5;
margin-bottom: 1.5rem;
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
flex-grow: 1;
}
/* Card footer */
.card-footer {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: auto;
}
/* Card category badge */
.card-category {
background: rgba(255, 255, 255, 0.15);
color: rgba(255, 255, 255, 0.9);
padding: 0.3rem 0.8rem;
border-radius: 12px;
font-size: 0.8em;
font-weight: 500;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
transition: all 0.3s ease;
}
/* Card arrow */
.card-arrow {
font-size: 1.2em;
color: rgba(255, 255, 255, 0.7);
transition: all 0.3s ease;
transform: translateX(0);
}
/* Card shine effect */
.card-shine {
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.1), transparent);
transform: skewX(-20deg);
transition: left 0.6s ease;
pointer-events: none;
}
/* Category spacer */
.category-spacer {
height: 2rem;
}
/* Responsive adjustments for cards */
@media (max-width: 768px) {
.cards-container {
grid-template-columns: 1fr;
gap: 1rem;
}
.card-content {
padding: 1.5rem;
}
.premium-card {
min-height: 180px;
}
.category-header {
margin: 2rem 0 1.5rem 0;
}
.main .block-container {
padding: 1.5rem !important;
margin: 1rem;
}
.dashboard-header {
padding: 2rem 1.5rem;
margin-bottom: 2rem;
}
.dashboard-header h1 {
font-size: 2.4em;
}
.dashboard-header p {
font-size: 1.1em;
}
}
/* Card entrance animations */
.premium-card {
animation: cardSlideIn 0.6s ease-out forwards;
opacity: 0;
}
@keyframes cardSlideIn {
from {
opacity: 0;
transform: translateY(30px) scale(0.95);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
/* Stagger animation delays */
.premium-card:nth-child(1) { animation-delay: 0.1s; }
.premium-card:nth-child(2) { animation-delay: 0.2s; }
.premium-card:nth-child(3) { animation-delay: 0.3s; }
.premium-card:nth-child(4) { animation-delay: 0.4s; }
.premium-card:nth-child(5) { animation-delay: 0.5s; }
.premium-card:nth-child(6) { animation-delay: 0.6s; }
/* Hide Streamlit elements */
.stApp > header {
visibility: hidden;
}
/* Custom scrollbar */
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: rgba(255, 255, 255, 0.1);
border-radius: 4px;
}
::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.3);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(255, 255, 255, 0.5);
}
/* Page entrance animation */
.main .block-container {
animation: fadeInUp 0.8s ease-out;
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
</style>
""", unsafe_allow_html=True)
def render_dashboard_header(title, description):
"""Render a standardized dashboard header."""
st.markdown(f"""
<div class="dashboard-header">
<h1>{title}</h1>
<p>{description}</p>
</div>
""", unsafe_allow_html=True)
def render_category_header(category_name):
"""Render a standardized category header."""
st.markdown(f"""
<div class="category-header">
<h2>{category_name}</h2>
<div class="category-line"></div>
</div>
""", unsafe_allow_html=True)
def render_card(icon, title, description, category, key_suffix="", help_text=""):
"""Render a standardized premium card with button."""
st.markdown(f"""
<div class="card-container">
<div class="premium-card">
<div class="card-glow"></div>
<div class="card-content">
<div class="card-icon">{icon}</div>
<div class="card-title">{title}</div>
<div class="card-description">{description}</div>
<div class="card-footer">
<span class="card-category">{category}</span>
<div class="card-arrow">→</div>
</div>
</div>
<div class="card-shine"></div>
</div>
</div>
""", unsafe_allow_html=True)
# Return button for functionality
return st.button(
f"Select {title}",
key=f"card_{key_suffix}",
help=help_text or f"Launch {title} - {description}",
use_container_width=True
)

View File

@@ -0,0 +1,331 @@
import streamlit as st
def apply_navigation_styles():
"""Apply navigation and UI setup specific styling."""
st.markdown("""
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap');
/* Main app styling for navigation */
.stApp {
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
}
/* 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: 'Inter', '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 */
.stButton > button {
border-radius: 8px;
font-weight: 500;
transition: all 0.3s ease;
margin-bottom: 0.25rem; /* Reduced from 0.5rem */
font-family: 'Inter', sans-serif;
}
.stButton > button:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}
/* Input field styling */
.stTextInput > div > div > input {
border-radius: 8px;
border: 1px solid rgba(0,0,0,0.1);
padding: 0.5rem 1rem;
font-family: 'Inter', sans-serif;
}
/* Checkbox styling */
.stCheckbox > label {
font-weight: 500;
font-family: 'Inter', sans-serif;
}
/* Expander styling */
.streamlit-expanderHeader {
font-weight: 500;
color: #2c3e50;
margin-bottom: 0.5rem;
font-family: 'Inter', sans-serif;
}
/* Success message styling */
.stSuccess {
background: linear-gradient(135deg, #43c6ac 0%, #191654 100%);
padding: 0.75rem;
border-radius: 8px;
color: white;
margin-bottom: 1rem;
font-family: 'Inter', sans-serif;
}
/* Error message styling */
.stError {
background: linear-gradient(135deg, #ff6b6b 0%, #ff8e8e 100%);
padding: 0.75rem;
border-radius: 8px;
color: white;
margin-bottom: 1rem;
font-family: 'Inter', sans-serif;
}
/* Info message styling */
.stInfo {
padding: 0.75rem;
margin-bottom: 1rem;
font-family: 'Inter', sans-serif;
}
/* Sidebar navigation styling */
.sidebar-nav {
padding: 0.5rem 0;
}
.nav-button {
width: 100%;
text-align: left;
padding: 0.5rem 1rem;
background: transparent;
border: none;
color: #2c3e50;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
margin: 0.2rem 0;
border-radius: 4px;
font-family: 'Inter', sans-serif;
}
.nav-button:hover {
background: rgba(0,0,0,0.05);
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%;
font-family: 'Inter', sans-serif;
}
/* 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;
}
/* Additional compact layout overrides for specific pages */
.compact-layout .main .block-container {
padding-top: 0.25rem !important;
padding-bottom: 0;
}
/* Hide Streamlit elements for cleaner navigation */
.stApp > header {
visibility: hidden;
}
/* Custom scrollbar for navigation */
.sidebar .stMarkdown::-webkit-scrollbar {
width: 6px;
}
.sidebar .stMarkdown::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0.1);
border-radius: 3px;
}
.sidebar .stMarkdown::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.3);
border-radius: 3px;
}
.sidebar .stMarkdown::-webkit-scrollbar-thumb:hover {
background: rgba(0, 0, 0, 0.5);
}
</style>
""", unsafe_allow_html=True)
def apply_compact_layout():
"""Apply compact layout styling for specific pages."""
st.markdown("""
<style>
.main .block-container {
padding-top: 0.25rem !important;
padding-bottom: 0;
}
</style>
""", unsafe_allow_html=True)

View File

@@ -0,0 +1,293 @@
import streamlit as st
from loguru import logger
from lib.ai_seo_tools.seo_structured_data import ai_structured_data
from lib.ai_seo_tools.content_title_generator import ai_title_generator
from lib.ai_seo_tools.meta_desc_generator import metadesc_generator_main
from lib.ai_seo_tools.image_alt_text_generator import alt_text_gen
from lib.ai_seo_tools.opengraph_generator import og_tag_generator
from lib.ai_seo_tools.optimize_images_for_upload import main_img_optimizer
from lib.ai_seo_tools.google_pagespeed_insights import google_pagespeed_insights
from lib.ai_seo_tools.on_page_seo_analyzer import analyze_onpage_seo
from lib.ai_seo_tools.weburl_seo_checker import url_seo_checker
from lib.ai_marketing_tools.ai_backlinker.backlinking_ui_streamlit import backlinking_ui
from lib.ai_seo_tools.content_gap_analysis.ui import ContentGapAnalysisUI
from lib.ai_seo_tools.content_calendar.ui.dashboard import ContentCalendarDashboard
from lib.alwrity_ui.dashboard_styles import apply_dashboard_style, render_dashboard_header, render_category_header, render_card
def render_content_gap_analysis():
"""Render the content gap analysis workflow interface."""
from lib.ai_seo_tools.content_gap_analysis.ui import ContentGapAnalysisUI
# Initialize and run the Content Gap Analysis UI
ui = ContentGapAnalysisUI()
ui.run()
def render_content_calendar():
"""Render the content calendar dashboard."""
import logging
import sys
from datetime import datetime
# Configure logging
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.StreamHandler(sys.stdout),
logging.FileHandler('content_calendar.log', mode='a')
]
)
logger = logging.getLogger('content_calendar')
try:
logger.info("Initializing Content Calendar Dashboard")
dashboard = ContentCalendarDashboard()
logger.info("Rendering Content Calendar Dashboard")
dashboard.render()
logger.info("Content Calendar Dashboard rendered successfully")
except Exception as e:
logger.error(f"Error rendering content calendar: {str(e)}", exc_info=True)
st.error(f"An error occurred while loading the content calendar: {str(e)}")
def render_seo_tools_dashboard():
"""Render a modern dashboard for SEO tools with premium glassmorphic design."""
# Apply common dashboard styling
apply_dashboard_style()
# Enhanced dashboard header with modern design
render_dashboard_header(
"🚀 SEO AI Power Suite",
"Dominate search rankings with our comprehensive AI-powered SEO toolkit. From keyword research to content optimization, master every aspect of search engine optimization."
)
# Define SEO tools organized by category
seo_tools = {
"Research & Strategy": {
"Color Analysis": {
"icon": "🎨",
"description": "Analyze website color schemes for optimal user experience and SEO performance",
"category": "Analysis",
"path": "color_analysis",
"features": ["Color Psychology", "Accessibility Check", "Brand Analysis", "Conversion Optimization"]
},
"Keyword Research": {
"icon": "🔑",
"description": "Discover high-impact keywords with advanced AI-powered research and competition analysis",
"category": "Research",
"path": "keyword_research",
"features": ["Keyword Discovery", "Competition Analysis", "Search Volume", "Difficulty Scoring"]
},
"SEO Audit": {
"icon": "🔍",
"description": "Comprehensive website analysis with actionable insights for improving search rankings",
"category": "Analysis",
"path": "seo_audit",
"features": ["Technical SEO", "Content Analysis", "Performance Check", "Mobile Optimization"]
}
},
"Content Optimization": {
"Content Optimizer": {
"icon": "📝",
"description": "Transform your content with AI-driven SEO optimization for maximum search visibility",
"category": "Optimization",
"path": "content_optimizer",
"features": ["Content Analysis", "SEO Scoring", "Readability Check", "Meta Optimization"]
},
"Meta Generator": {
"icon": "🏷️",
"description": "Create compelling meta titles and descriptions that boost click-through rates",
"category": "Optimization",
"path": "meta_generator",
"features": ["Title Generation", "Description Writing", "Character Optimization", "SERP Preview"]
},
"Schema Markup": {
"icon": "🏗️",
"description": "Generate structured data markup to enhance search result appearance",
"category": "Technical",
"path": "schema_markup",
"features": ["Rich Snippets", "Local SEO", "Product Markup", "FAQ Schema"]
}
},
"Analysis & Tracking": {
"Rank Tracker": {
"icon": "📊",
"description": "Monitor keyword rankings and track your SEO progress with detailed analytics",
"category": "Analytics",
"path": "rank_tracker",
"features": ["Position Tracking", "Progress Analytics", "Competitor Monitoring", "Ranking Reports"]
},
"Backlink Analyzer": {
"icon": "🔗",
"description": "Analyze your backlink profile and discover new link building opportunities",
"category": "Analysis",
"path": "backlink_analyzer",
"features": ["Link Analysis", "Authority Metrics", "Anchor Text Analysis", "Toxic Link Detection"]
},
"Site Speed Test": {
"icon": "",
"description": "Evaluate website performance and get optimization recommendations",
"category": "Performance",
"path": "speed_test",
"features": ["Speed Analysis", "Core Web Vitals", "Optimization Tips", "Mobile Performance"]
}
}
}
# Render categories and tools
for category, tools in seo_tools.items():
# Render category header
render_category_header(category)
# Create responsive grid for tools in this category
cols = st.columns(3)
for idx, (tool_name, details) in enumerate(tools.items()):
with cols[idx % 3]:
# Use the common card renderer
if render_card(
icon=details['icon'],
title=tool_name,
description=details['description'],
category=details['category'],
key_suffix=f"seo_{tool_name.replace(' ', '_')}",
help_text=f"Open {tool_name} - {details['description'][:50]}..."
):
# Set query parameters to redirect to the specific tool
st.query_params["tool"] = details["path"]
st.rerun()
# Add SEO insights section
st.markdown("""
<div style="margin-top: 3rem;">
<div class="dashboard-header" style="margin-bottom: 2rem;">
<h1 style="font-size: 2.2em;">🎯 SEO Success Features</h1>
<p>Comprehensive tools designed to boost your search engine rankings and drive organic traffic growth.</p>
</div>
</div>
""", unsafe_allow_html=True)
# SEO insights grid
insight_cols = st.columns(2)
insights = [
{
"title": "🤖 AI-Powered Analysis",
"description": "Advanced machine learning algorithms analyze your content and provide data-driven optimization recommendations."
},
{
"title": "📈 Real-Time Tracking",
"description": "Monitor your SEO performance with live ranking updates and comprehensive progress analytics."
},
{
"title": "🎯 Competitor Intelligence",
"description": "Stay ahead of the competition with detailed analysis of competitor strategies and opportunities."
},
{
"title": "🚀 Technical Excellence",
"description": "Comprehensive technical SEO analysis covering Core Web Vitals, mobile optimization, and site architecture."
}
]
for idx, insight in enumerate(insights):
with insight_cols[idx % 2]:
st.markdown(f"""
<div class="premium-card" style="min-height: 160px; cursor: default;">
<div class="card-glow"></div>
<div class="card-content">
<div class="card-title" style="margin-bottom: 0.8rem;">{insight['title']}</div>
<div class="card-description" style="margin-bottom: 0;">{insight['description']}</div>
</div>
<div class="card-shine"></div>
</div>
""", unsafe_allow_html=True)
# Close dashboard container
st.markdown('</div>', unsafe_allow_html=True)
def ai_seo_tools():
"""Render the SEO tools dashboard with premium glassmorphic design."""
logger.info("Starting SEO Tools Dashboard")
# Apply common dashboard styling
apply_dashboard_style()
# Check if a specific tool is selected
selected_tool = st.query_params.get("tool")
if selected_tool:
# Map tool paths to their respective functions
tool_functions = {
# Individual tools
"structured_data": ai_structured_data,
"blog_title": ai_title_generator,
"meta_description": metadesc_generator_main,
"alt_text": alt_text_gen,
"opengraph": og_tag_generator,
"image_optimizer": main_img_optimizer,
"pagespeed": google_pagespeed_insights,
"onpage_seo": analyze_onpage_seo,
"url_checker": url_seo_checker,
"backlinking": backlinking_ui,
# Tool combinations
"content_optimization": lambda: run_tool_combination([
ai_title_generator,
metadesc_generator_main,
ai_structured_data
], "Content Optimization Suite"),
"technical_audit": lambda: run_tool_combination([
google_pagespeed_insights,
analyze_onpage_seo,
url_seo_checker
], "Technical SEO Audit"),
"image_optimization": lambda: run_tool_combination([
alt_text_gen,
main_img_optimizer
], "Image Optimization Suite"),
"social_optimization": lambda: run_tool_combination([
og_tag_generator,
backlinking_ui
], "Social Media Optimization"),
# Add Content Gap Analysis and Content Calendar
"content_gap_analysis": render_content_gap_analysis,
"content_calendar": render_content_calendar
}
if selected_tool in tool_functions:
# Clear any existing content
st.empty()
# Execute the selected tool's function
tool_functions[selected_tool]()
else:
st.error(f"Invalid tool selected: {selected_tool}")
render_seo_tools_dashboard()
else:
# Show the dashboard if no tool is selected
render_seo_tools_dashboard()
def run_tool_combination(tools, combination_name):
"""Run a combination of tools and provide cross-tool analysis."""
st.markdown(f"# {combination_name}")
st.markdown("Running comprehensive analysis...")
# Create tabs for each tool in the combination
tabs = st.tabs([f"Step {i+1}" for i in range(len(tools))])
# Run each tool in its own tab
for i, (tab, tool) in enumerate(zip(tabs, tools)):
with tab:
st.markdown(f"### Step {i+1}")
tool()
# Add cross-tool analysis section
st.markdown("## 📊 Cross-Tool Analysis")
st.markdown("Analyzing results across all tools...")
# Add recommendations based on combined results
st.markdown("## 💡 Recommendations")
st.markdown("Based on the combined analysis, here are the key recommendations:")
# Add a button to export the complete analysis
if st.button("📥 Export Complete Analysis", use_container_width=True):
st.info("Analysis export functionality coming soon!")

View File

@@ -0,0 +1,973 @@
import streamlit as st
from loguru import logger
import asyncio
from lib.web_crawlers.async_web_crawler import AsyncWebCrawlerService
from lib.personalization.style_analyzer import StyleAnalyzer
from lib.alwrity_ui.dashboard_styles import apply_dashboard_style, render_dashboard_header
import sys
# Configure logger
logger.remove() # Remove default handler
logger.add(
"logs/settings_page.log",
rotation="500 MB",
retention="10 days",
level="DEBUG",
format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}",
backtrace=True,
diagnose=True
)
logger.add(
sys.stdout,
level="INFO",
format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{message}</cyan>"
)
def display_style_analysis(analysis_results: dict):
"""Display the style analysis results in a structured format with premium styling."""
try:
# Writing Style Section
st.markdown("""
<div class="analysis-section">
<div class="section-icon">🎨</div>
<h3>Writing Style Analysis</h3>
</div>
""", unsafe_allow_html=True)
writing_style = analysis_results.get("writing_style", {})
col1, col2 = st.columns(2)
with col1:
st.markdown(f"""
<div class="analysis-card">
<div class="metric-item">
<span class="metric-label">Tone:</span>
<span class="metric-value">{writing_style.get("tone", "N/A")}</span>
</div>
<div class="metric-item">
<span class="metric-label">Voice:</span>
<span class="metric-value">{writing_style.get("voice", "N/A")}</span>
</div>
</div>
""", unsafe_allow_html=True)
with col2:
st.markdown(f"""
<div class="analysis-card">
<div class="metric-item">
<span class="metric-label">Complexity:</span>
<span class="metric-value">{writing_style.get("complexity", "N/A")}</span>
</div>
<div class="metric-item">
<span class="metric-label">Engagement:</span>
<span class="metric-value">{writing_style.get("engagement_level", "N/A")}</span>
</div>
</div>
""", unsafe_allow_html=True)
# Content Characteristics Section
st.markdown("""
<div class="analysis-section">
<div class="section-icon">📊</div>
<h3>Content Characteristics</h3>
</div>
""", unsafe_allow_html=True)
content_chars = analysis_results.get("content_characteristics", {})
col1, col2 = st.columns(2)
with col1:
st.markdown(f"""
<div class="analysis-card">
<div class="metric-item">
<span class="metric-label">Sentence Structure:</span>
<span class="metric-value">{content_chars.get("sentence_structure", "N/A")}</span>
</div>
<div class="metric-item">
<span class="metric-label">Vocabulary Level:</span>
<span class="metric-value">{content_chars.get("vocabulary_level", "N/A")}</span>
</div>
</div>
""", unsafe_allow_html=True)
with col2:
st.markdown(f"""
<div class="analysis-card">
<div class="metric-item">
<span class="metric-label">Organization:</span>
<span class="metric-value">{content_chars.get("paragraph_organization", "N/A")}</span>
</div>
<div class="metric-item">
<span class="metric-label">Content Flow:</span>
<span class="metric-value">{content_chars.get("content_flow", "N/A")}</span>
</div>
</div>
""", unsafe_allow_html=True)
# Target Audience Section
st.markdown("""
<div class="analysis-section">
<div class="section-icon">🎯</div>
<h3>Target Audience</h3>
</div>
""", unsafe_allow_html=True)
target_audience = analysis_results.get("target_audience", {})
col1, col2 = st.columns(2)
with col1:
st.markdown(f"""
<div class="analysis-card">
<div class="metric-item">
<span class="metric-label">Demographics:</span>
<span class="metric-value">{', '.join(target_audience.get("demographics", ["N/A"]))}</span>
</div>
<div class="metric-item">
<span class="metric-label">Expertise Level:</span>
<span class="metric-value">{target_audience.get("expertise_level", "N/A")}</span>
</div>
</div>
""", unsafe_allow_html=True)
with col2:
st.markdown(f"""
<div class="analysis-card">
<div class="metric-item">
<span class="metric-label">Industry Focus:</span>
<span class="metric-value">{target_audience.get("industry_focus", "N/A")}</span>
</div>
<div class="metric-item">
<span class="metric-label">Geographic Focus:</span>
<span class="metric-value">{target_audience.get("geographic_focus", "N/A")}</span>
</div>
</div>
""", unsafe_allow_html=True)
# Recommended Settings Section
st.markdown("""
<div class="analysis-section">
<div class="section-icon">⚙️</div>
<h3>Recommended Settings</h3>
</div>
""", unsafe_allow_html=True)
recommended = analysis_results.get("recommended_settings", {})
st.markdown(f"""
<div class="recommendations-grid">
<div class="recommendation-card">
<div class="rec-icon">🎭</div>
<div class="rec-label">Writing Tone</div>
<div class="rec-value">{recommended.get("writing_tone", "N/A")}</div>
</div>
<div class="recommendation-card">
<div class="rec-icon">👥</div>
<div class="rec-label">Target Audience</div>
<div class="rec-value">{recommended.get("target_audience", "N/A")}</div>
</div>
<div class="recommendation-card">
<div class="rec-icon">📝</div>
<div class="rec-label">Content Type</div>
<div class="rec-value">{recommended.get("content_type", "N/A")}</div>
</div>
<div class="recommendation-card">
<div class="rec-icon">🎨</div>
<div class="rec-label">Creativity Level</div>
<div class="rec-value">{recommended.get("creativity_level", "N/A")}</div>
</div>
</div>
""", unsafe_allow_html=True)
except Exception as e:
logger.error(f"Error displaying style analysis: {str(e)}")
st.error(f"Error displaying analysis results: {str(e)}")
def render_settings_page():
"""Renders the settings page with premium glassmorphic design and all configuration options in tabs"""
# Apply common dashboard styling
apply_dashboard_style()
# Add settings-specific CSS for tabs and form elements
st.markdown("""
<style>
/* Settings-specific overrides and additions */
.main .block-container {
padding: 1rem 1.5rem 1.5rem 1.5rem !important;
margin: 1rem auto !important;
}
.element-container {
margin-bottom: 0.3rem !important;
}
.stMarkdown {
margin: 0 !important;
padding: 0 !important;
margin-bottom: 0.3rem !important;
}
/* Enhanced tab styling for settings */
.stTabs [data-baseweb="tab-list"] {
gap: 0.5rem !important;
background: rgba(255, 255, 255, 0.35) !important;
backdrop-filter: blur(30px) !important;
border-radius: 18px !important;
padding: 0.8rem !important;
border: 3px solid rgba(255, 255, 255, 0.4) !important;
margin-bottom: 1.5rem !important;
box-shadow:
0 20px 40px rgba(0, 0, 0, 0.25),
inset 0 3px 0 rgba(255, 255, 255, 0.5) !important;
}
.stTabs [data-baseweb="tab"] {
background: rgba(255, 255, 255, 0.3) !important;
backdrop-filter: blur(25px) !important;
border-radius: 14px !important;
color: #ffffff !important;
border: 2px solid rgba(255, 255, 255, 0.35) !important;
padding: 1rem 2rem !important;
font-weight: 800 !important;
font-size: 1.05rem !important;
transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1) !important;
margin: 0 !important;
min-height: 50px !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
text-shadow: 0 3px 6px rgba(0, 0, 0, 0.6) !important;
box-shadow:
0 8px 25px rgba(0, 0, 0, 0.2),
inset 0 2px 0 rgba(255, 255, 255, 0.4) !important;
font-family: 'Inter', sans-serif !important;
}
.stTabs [data-baseweb="tab"]:hover {
background: rgba(255, 255, 255, 0.4) !important;
backdrop-filter: blur(30px) !important;
color: #ffffff !important;
border-color: rgba(255, 255, 255, 0.5) !important;
transform: translateY(-2px) !important;
box-shadow:
0 15px 35px rgba(0, 0, 0, 0.3),
inset 0 3px 0 rgba(255, 255, 255, 0.5) !important;
}
.stTabs [aria-selected="true"] {
background: rgba(255, 255, 255, 0.5) !important;
backdrop-filter: blur(35px) !important;
color: #ffffff !important;
border-color: rgba(255, 255, 255, 0.6) !important;
box-shadow:
0 15px 35px rgba(0, 0, 0, 0.3),
inset 0 3px 0 rgba(255, 255, 255, 0.6),
0 0 0 2px rgba(255, 255, 255, 0.3) !important;
transform: translateY(-1px) !important;
font-weight: 900 !important;
text-shadow: 0 3px 8px rgba(0, 0, 0, 0.7) !important;
}
/* Settings sections */
.settings-section {
background: rgba(255, 255, 255, 0.15);
backdrop-filter: blur(25px);
border-radius: 16px;
padding: 1.5rem;
margin-bottom: 1.5rem;
border: 2px solid rgba(255, 255, 255, 0.25);
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.15);
position: relative;
overflow: hidden;
}
.settings-section::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 2px;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.5), transparent);
opacity: 0.9;
}
.settings-section h2 {
color: #ffffff !important;
font-size: 1.6em !important;
font-weight: 800 !important;
margin-bottom: 1.2rem !important;
margin-top: 0 !important;
text-shadow: 0 3px 12px rgba(0, 0, 0, 0.5) !important;
display: flex;
align-items: center;
gap: 0.6rem;
letter-spacing: -0.01em;
padding-bottom: 0.8rem;
border-bottom: 2px solid rgba(255, 255, 255, 0.2);
font-family: 'Inter', sans-serif !important;
}
/* Form elements with maximum visibility */
.stSelectbox > div > div,
.stSelectbox div[data-baseweb="select"] > div {
background: rgba(255, 255, 255, 0.35) !important;
backdrop-filter: blur(30px) !important;
border: 3px solid rgba(255, 255, 255, 0.5) !important;
border-radius: 12px !important;
color: #ffffff !important;
box-shadow:
0 10px 30px rgba(0, 0, 0, 0.2),
inset 0 2px 0 rgba(255, 255, 255, 0.4) !important;
min-height: 45px !important;
font-weight: 700 !important;
font-size: 1rem !important;
font-family: 'Inter', sans-serif !important;
}
.stTextInput > div > div > input,
.stTextArea > div > div > textarea,
.stNumberInput > div > div > input {
background: rgba(255, 255, 255, 0.35) !important;
backdrop-filter: blur(30px) !important;
border: 3px solid rgba(255, 255, 255, 0.5) !important;
border-radius: 12px !important;
color: #ffffff !important;
box-shadow:
0 10px 30px rgba(0, 0, 0, 0.2),
inset 0 2px 0 rgba(255, 255, 255, 0.4) !important;
min-height: 45px !important;
font-weight: 700 !important;
font-size: 1rem !important;
font-family: 'Inter', sans-serif !important;
}
.stTextInput > div > div > input:focus,
.stTextArea > div > div > textarea:focus,
.stNumberInput > div > div > input:focus {
border-color: rgba(255, 255, 255, 0.7) !important;
box-shadow:
0 0 0 4px rgba(255, 255, 255, 0.4),
0 15px 35px rgba(0, 0, 0, 0.25) !important;
background: rgba(255, 255, 255, 0.4) !important;
}
.stTextInput > div > div > input::placeholder {
color: rgba(255, 255, 255, 0.8) !important;
font-weight: 600 !important;
}
/* Enhanced labels */
.stMarkdown p, .stSelectbox label, .stTextInput label, .stTextArea label, .stSlider label, .stNumberInput label {
color: #ffffff !important;
font-weight: 800 !important;
text-shadow:
0 2px 6px rgba(0, 0, 0, 0.5),
0 1px 3px rgba(0, 0, 0, 0.7) !important;
font-size: 1.05rem !important;
margin-bottom: 0.4rem !important;
font-family: 'Inter', sans-serif !important;
letter-spacing: -0.01em;
}
/* Slider styling */
.stSlider > div > div > div {
background: rgba(255, 255, 255, 0.5) !important;
border-radius: 8px !important;
height: 8px !important;
}
.stSlider > div > div > div > div {
background: #ffffff !important;
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25) !important;
width: 20px !important;
height: 20px !important;
}
/* Analysis results styling */
.analysis-section {
display: flex;
align-items: center;
gap: 1rem;
margin: 2rem 0 1rem 0;
padding: 1rem;
background: rgba(255, 255, 255, 0.08);
backdrop-filter: blur(15px);
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.15);
}
.section-icon {
font-size: 1.5em;
color: #ffffff;
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
.analysis-section h3 {
color: #ffffff;
font-size: 1.2em;
font-weight: 600;
margin: 0;
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
.analysis-card {
background: rgba(255, 255, 255, 0.08);
backdrop-filter: blur(15px);
border-radius: 12px;
padding: 1.5rem;
border: 1px solid rgba(255, 255, 255, 0.15);
margin-bottom: 1rem;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
}
.metric-item {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.8rem;
padding-bottom: 0.8rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.metric-item:last-child {
margin-bottom: 0;
padding-bottom: 0;
border-bottom: none;
}
.metric-label {
color: rgba(255, 255, 255, 0.8);
font-weight: 500;
font-size: 0.9em;
}
.metric-value {
color: #ffffff;
font-weight: 600;
font-size: 0.9em;
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
}
.recommendations-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
margin-top: 1rem;
}
.recommendation-card {
background: rgba(255, 255, 255, 0.08);
backdrop-filter: blur(15px);
border-radius: 12px;
padding: 1.5rem;
border: 1px solid rgba(255, 255, 255, 0.15);
text-align: center;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
}
.recommendation-card:hover {
transform: translateY(-2px);
background: rgba(255, 255, 255, 0.12);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
}
.rec-icon {
font-size: 2em;
margin-bottom: 0.5rem;
color: #ffffff;
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
.rec-label {
color: rgba(255, 255, 255, 0.8);
font-size: 0.9em;
font-weight: 500;
margin-bottom: 0.5rem;
}
.rec-value {
color: #ffffff;
font-weight: 600;
font-size: 1em;
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
}
/* Status messages */
.stSuccess {
background: rgba(46, 160, 67, 0.2) !important;
backdrop-filter: blur(15px) !important;
border: 1px solid rgba(46, 160, 67, 0.3) !important;
border-radius: 12px !important;
color: #ffffff !important;
}
.stError {
background: rgba(255, 75, 75, 0.2) !important;
backdrop-filter: blur(15px) !important;
border: 1px solid rgba(255, 75, 75, 0.3) !important;
border-radius: 12px !important;
color: #ffffff !important;
}
.stWarning {
background: rgba(255, 196, 9, 0.2) !important;
backdrop-filter: blur(15px) !important;
border: 1px solid rgba(255, 196, 9, 0.3) !important;
border-radius: 12px !important;
color: #ffffff !important;
}
.stStatus {
background: rgba(255, 255, 255, 0.08) !important;
backdrop-filter: blur(15px) !important;
border: 1px solid rgba(255, 255, 255, 0.15) !important;
border-radius: 12px !important;
}
</style>
""", unsafe_allow_html=True)
# Use the common dashboard header
render_dashboard_header(
"⚙️ Settings & Configuration",
"Customize your AI experience with precision controls for content generation, personalization, and optimization. Fine-tune every aspect to match your unique requirements and style."
)
# Create tabs for different settings categories with premium styling
tabs = st.tabs([
"📝 Content",
"🖼️ Images",
"🤖 LLM",
"🔍 Search",
"🎨 AI Personalization"
])
# Content Settings Tab
with tabs[0]:
st.markdown("""
<div class="settings-section">
<h2>📝 Content Personalization</h2>
</div>
""", unsafe_allow_html=True)
col1, col2 = st.columns(2)
with col1:
blog_length = st.text_input(
"**Content Length (words)**",
value="2000",
key="settings_blog_length",
help="Approximate word count for blogs. Note: Actual length may vary based on GPT provider and max token count."
)
blog_tone_options = ["Casual", "Professional", "How-to", "Beginner", "Research", "Programming", "Social Media", "Customize"]
blog_tone = st.selectbox(
"**Content Tone**",
options=blog_tone_options,
key="settings_blog_tone",
help="Select the desired tone for the blog content."
)
# Initialize custom_tone variable
custom_tone = ""
if blog_tone == "Customize":
custom_tone = st.text_input(
"Enter the tone of your content",
key="settings_custom_tone",
help="Specify the tone of your content."
)
if custom_tone:
blog_tone = custom_tone
else:
st.warning("Please specify the tone of your content.")
blog_demographic_options = ["Professional", "Gen-Z", "Tech-savvy", "Student", "Digital Marketing", "Customize"]
blog_demographic = st.selectbox(
"**Target Audience**",
options=blog_demographic_options,
key="settings_blog_demographic",
help="Select the primary audience for the blog content."
)
with col2:
blog_type = st.selectbox(
"**Content Type**",
options=["Informational", "Commercial", "Company", "News", "Finance", "Competitor", "Programming", "Scholar"],
key="settings_blog_type",
help="Select the category that best describes the blog content."
)
blog_language = st.selectbox(
"**Content Language**",
options=["English", "Spanish", "German", "Chinese", "Arabic", "Nepali", "Hindi", "Hindustani", "Customize"],
key="settings_blog_language",
help="Select the language in which the blog will be written."
)
blog_output_format = st.selectbox(
"**Content Output Format**",
options=["markdown", "HTML", "plaintext"],
key="settings_blog_output_format",
help="Select the format for the blog output."
)
# Images Settings Tab
with tabs[1]:
st.markdown("""
<div class="settings-section">
<h2>🖼️ Images Personalization</h2>
</div>
""", unsafe_allow_html=True)
col1, col2 = st.columns(2)
with col1:
image_generation_model = st.selectbox(
"**Image Generation Model**",
options=["stable-diffusion", "dalle2", "dalle3"],
key="settings_image_model",
help="Select the model to generate images for the blog."
)
with col2:
number_of_blog_images = st.number_input(
"**Number of Blog Images**",
value=1,
min_value=1,
max_value=10,
key="settings_number_of_images",
help="Specify the number of images to include in the blog."
)
# LLM Settings Tab
with tabs[2]:
st.markdown("""
<div class="settings-section">
<h2>🤖 LLM Personalization</h2>
</div>
""", unsafe_allow_html=True)
col1, col2 = st.columns(2)
with col1:
gpt_provider = st.selectbox(
"**GPT Provider**",
options=["google", "openai", "minstral"],
key="settings_gpt_provider",
help="Select the provider for the GPT model."
)
model = st.text_input(
"**Model**",
value="gemini-1.5-flash-latest",
key="settings_model",
help="Specify the model version to use from the selected provider."
)
temperature = st.slider(
"**Temperature**",
min_value=0.1,
max_value=1.0,
value=0.7,
step=0.1,
key="settings_temperature",
help="Controls the creativity level of the generated text."
)
max_tokens = st.selectbox(
"**Max Tokens**",
options=[500, 1000, 2000, 4000, 16000, 32000, 64000],
index=3,
key="settings_max_tokens",
help="Maximum length of the output sequence."
)
with col2:
top_p = st.slider(
"**Top-p**",
min_value=0.0,
max_value=1.0,
value=0.9,
step=0.1,
key="settings_top_p",
help="Controls diversity in text generation."
)
frequency_penalty = st.slider(
"**Frequency Penalty**",
min_value=0.0,
max_value=2.0,
value=1.0,
step=0.1,
key="settings_frequency_penalty",
help="Reduces word repetition in output."
)
# Search Settings Tab
with tabs[3]:
st.markdown("""
<div class="settings-section">
<h2>🔍 Search Engine Personalization</h2>
</div>
""", unsafe_allow_html=True)
col1, col2 = st.columns(2)
with col1:
geographic_location = st.selectbox(
"**Geographic Location**",
options=["us", "in", "fr", "cn"],
key="settings_geographic_location",
help="Select the geographic location for tailoring search results."
)
search_language = st.selectbox(
"**Search Language**",
options=["en", "zn-cn", "de", "hi"],
key="settings_search_language",
help="Select the language for the search results."
)
number_of_results = st.number_input(
"**Number of Results**",
value=10,
min_value=1,
max_value=20,
key="settings_number_of_results",
help="Specify the number of search results to retrieve."
)
with col2:
time_range = st.selectbox(
"**Time Range**",
options=["anytime", "past day", "past week", "past month", "past year"],
key="settings_time_range",
help="Select the time range for filtering search results."
)
include_domains = st.text_input(
"**Include Domains**",
value="",
key="settings_include_domains",
help="List specific domains to include in search results (comma-separated)."
)
similar_url = st.text_input(
"**Similar URL**",
value="",
key="settings_similar_url",
help="Provide a URL to find similar results."
)
# AI Personalization Tab
with tabs[4]:
st.markdown("""
<div class="settings-section">
<h2>🎨 AI Style Analysis</h2>
</div>
""", unsafe_allow_html=True)
st.markdown("""
<div class="analysis-card" style="margin-bottom: 2rem;">
<p style="color: rgba(255, 255, 255, 0.9); font-size: 1.1em; margin: 0; line-height: 1.6;">
Enter a website URL or provide content samples to analyze your writing style and get personalized recommendations for optimal AI content generation.
</p>
</div>
""", unsafe_allow_html=True)
# Create two columns for the layout
col1, col2 = st.columns([2, 1])
with col1:
# Website URL input
st.markdown("#### 🌐 Website URL Analysis")
url = st.text_input(
"Enter your website URL",
placeholder="https://example.com",
key="settings_website_url",
help="Provide your website URL to analyze your content style. Leave empty if you want to provide written samples instead."
)
# Alternative: Written samples
if not url:
st.markdown("#### 📝 Written Samples")
st.markdown("""
<div class="analysis-card">
<p style="color: rgba(255, 255, 255, 0.9); margin: 0; line-height: 1.6;">
No website URL? No problem! You can provide written samples of your content instead.
Share your best articles, blog posts, or any content that represents your writing style.
</p>
</div>
""", unsafe_allow_html=True)
samples = st.text_area(
"Paste your content samples here",
key="settings_content_samples",
help="Paste 2-3 samples of your best content. This helps ALwrity understand your writing style.",
height=200
)
with col2:
st.markdown("#### 🎯 Analysis Features")
st.markdown("""
<div class="analysis-card">
<div style="color: rgba(255, 255, 255, 0.9); line-height: 1.6;">
<p><strong>✨ Writing Style:</strong> Tone, voice, complexity analysis</p>
<p><strong>📊 Content Analysis:</strong> Structure and vocabulary assessment</p>
<p><strong>🎯 Audience Insights:</strong> Target demographic identification</p>
<p><strong>⚙️ AI Recommendations:</strong> Personalized settings optimization</p>
</div>
</div>
""", unsafe_allow_html=True)
# Add spacing between categories
st.markdown("<div style='height: 20px'></div>", unsafe_allow_html=True)
if st.button("🎨 Analyze Writing Style", use_container_width=True, key="settings_analyze_style", type="primary"):
if url:
with st.status("Starting style analysis...", expanded=True) as status:
try:
# Step 1: Initialize crawler
status.update(label="Step 1/4: Initializing web crawler...", state="running")
crawler_service = AsyncWebCrawlerService()
# Step 2: Crawl website
status.update(label="Step 2/4: Crawling website content...", state="running")
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
result = loop.run_until_complete(crawler_service.crawl_website(url))
loop.close()
if result.get('success', False):
content = result.get('content', {})
# Step 3: Initialize style analyzer
status.update(label="Step 3/4: Analyzing content style...", state="running")
style_analyzer = StyleAnalyzer()
# Step 4: Perform style analysis
status.update(label="Step 4/4: Generating style recommendations...", state="running")
style_analysis = style_analyzer.analyze_content_style(content)
if style_analysis.get('error'):
status.update(label="Analysis failed", state="error")
st.error(f"Style analysis failed: {style_analysis['error']}")
else:
status.update(label="Analysis complete!", state="complete")
# Display style analysis results
display_style_analysis(style_analysis)
# Display original content in tabs
tab1, tab2, tab3 = st.tabs(["📄 Content", "📋 Metadata", "🔗 Links"])
with tab1:
st.markdown("#### Main Content")
st.markdown(f"""
<div class="analysis-card">
<div style="color: rgba(255, 255, 255, 0.9); line-height: 1.6;">
{content.get('main_content', 'No content found')}
</div>
</div>
""", unsafe_allow_html=True)
with tab2:
st.markdown("#### Website Metadata")
st.markdown(f"""
<div class="analysis-card">
<div class="metric-item">
<span class="metric-label">Title:</span>
<span class="metric-value">{content.get('title', 'No title found')}</span>
</div>
<div class="metric-item">
<span class="metric-label">Description:</span>
<span class="metric-value">{content.get('description', 'No description found')}</span>
</div>
</div>
""", unsafe_allow_html=True)
with tab3:
st.markdown("#### Extracted Links")
links = content.get('links', [])
if links:
for link in links[:10]: # Show first 10 links
st.markdown(f"""
<div class="analysis-card" style="margin-bottom: 0.5rem;">
<a href="{link.get('href', '')}" target="_blank" style="color: rgba(255, 255, 255, 0.9); text-decoration: none;">
{link.get('text', 'No text')[:80]}...
</a>
</div>
""", unsafe_allow_html=True)
else:
st.markdown("No links found in the content.")
else:
status.update(label="Crawling failed", state="error")
st.error("Failed to crawl the website. Please check the URL and try again.")
except Exception as e:
status.update(label="Analysis failed", state="error")
st.error(f"An error occurred during analysis: {str(e)}")
elif samples:
with st.status("Starting style analysis...", expanded=True) as status:
try:
# Initialize style analyzer
status.update(label="Analyzing content style...", state="running")
style_analyzer = StyleAnalyzer()
# Perform style analysis
style_analysis = style_analyzer.analyze_content_style({"main_content": samples})
if style_analysis.get('error'):
status.update(label="Analysis failed", state="error")
st.error(f"Style analysis failed: {style_analysis['error']}")
else:
status.update(label="Analysis complete!", state="complete")
# Display style analysis results
display_style_analysis(style_analysis)
except Exception as e:
status.update(label="Analysis failed", state="error")
st.error(f"An error occurred during analysis: {str(e)}")
else:
st.warning("Please provide either a website URL or content samples to analyze.")
# Save Settings Button with premium styling
st.markdown("<div style='height: 2rem'></div>", unsafe_allow_html=True)
if st.button("💾 Save All Settings", type="primary", use_container_width=True, key="settings_save_button"):
# Save all settings to session state
st.session_state.update({
'blog_length': blog_length,
'blog_tone': blog_tone,
'blog_demographic': blog_demographic,
'blog_type': blog_type,
'blog_language': blog_language,
'blog_output_format': blog_output_format,
'image_generation_model': image_generation_model,
'number_of_blog_images': number_of_blog_images,
'gpt_provider': gpt_provider,
'model': model,
'temperature': temperature,
'top_p': top_p,
'max_tokens': max_tokens,
'frequency_penalty': frequency_penalty,
'geographic_location': geographic_location,
'search_language': search_language,
'number_of_results': number_of_results,
'time_range': time_range,
'include_domains': include_domains,
'similar_url': similar_url
})
st.success("✅ Settings saved successfully! Your preferences have been applied to all AI tools.")
# Show a summary of saved settings
st.markdown("""
<div class="analysis-card" style="margin-top: 1rem;">
<h4 style="color: #ffffff; margin-bottom: 1rem;">📋 Settings Summary</h4>
<div style="color: rgba(255, 255, 255, 0.9); line-height: 1.6;">
<p><strong>Content:</strong> {length} words, {tone} tone, {audience} audience</p>
<p><strong>Images:</strong> {images} images using {model}</p>
<p><strong>AI Model:</strong> {provider} - {ai_model}</p>
<p><strong>Search:</strong> {location} region, {results} results</p>
</div>
</div>
""".format(
length=blog_length,
tone=blog_tone,
audience=blog_demographic,
images=number_of_blog_images,
model=image_generation_model,
provider=gpt_provider,
ai_model=model,
location=geographic_location,
results=number_of_results
), unsafe_allow_html=True)

View File

@@ -0,0 +1,116 @@
import streamlit as st
from lib.alwrity_ui.dashboard_styles import apply_dashboard_style, render_dashboard_header, render_card
from loguru import logger
def render_social_tools_dashboard():
"""Render the social media tools dashboard with premium glassmorphic design."""
logger.info("Starting Social Media Tools Dashboard")
# Apply common dashboard styling
apply_dashboard_style()
# Render dashboard header
render_dashboard_header(
"📱 AI Social Media Tools",
"Create engaging social media content across all major platforms with our specialized AI writers. From viral posts to professional updates, we've got you covered."
)
# Define social tools with enhanced details and platform-specific styling
social_tools = {
"Facebook": {
"icon": "📘",
"description": "Create engaging Facebook posts, stories, and ads that drive meaningful interactions and build community",
"category": "Social Network",
"path": "facebook",
"features": ["Post Generation", "Story Creation", "Ad Copy", "Community Management"]
},
"LinkedIn": {
"icon": "💼",
"description": "Generate professional LinkedIn content, articles, and networking posts that enhance your career presence",
"category": "Professional",
"path": "linkedin",
"features": ["Professional Posts", "Article Writing", "Network Building", "Career Content"]
},
"Twitter": {
"icon": "🐦",
"description": "Craft viral tweets, threads, and engaging content that sparks conversations and grows your following",
"category": "Microblogging",
"path": "twitter",
"features": ["Tweet Generation", "Thread Creation", "Hashtag Strategy", "Viral Content"]
},
"Instagram": {
"icon": "📸",
"description": "Create captivating Instagram captions, stories, and content that showcases your brand beautifully",
"category": "Visual Content",
"path": "instagram",
"features": ["Caption Writing", "Story Content", "Hashtag Research", "Visual Strategy"]
},
"YouTube": {
"icon": "🎥",
"description": "Generate compelling video scripts, descriptions, and content strategies for your YouTube channel",
"category": "Video Content",
"path": "youtube",
"features": ["Script Writing", "Video Descriptions", "SEO Optimization", "Content Planning"]
}
}
# Create a responsive grid of premium cards
cols = st.columns(3)
for idx, (platform, details) in enumerate(social_tools.items()):
with cols[idx % 3]:
# Use the common card renderer
if render_card(
icon=details['icon'],
title=platform,
description=details['description'],
category=details['category'],
key_suffix=f"social_{platform}",
help_text=f"Open {platform} content creation tools - {details['description'][:50]}..."
):
# Set query parameters to redirect to the specific tool
st.query_params["tool"] = details["path"]
st.rerun()
# Add feature showcase section
st.markdown("""
<div style="margin-top: 3rem;">
<div class="dashboard-header" style="margin-bottom: 2rem;">
<h1 style="font-size: 2.2em;">✨ Platform Features</h1>
<p>Each platform comes with specialized AI tools designed for optimal engagement and growth.</p>
</div>
</div>
""", unsafe_allow_html=True)
# Feature grid
feature_cols = st.columns(2)
features = [
{
"title": "🎯 Smart Content Generation",
"description": "AI-powered content creation tailored to each platform's unique audience and format requirements."
},
{
"title": "📊 Engagement Optimization",
"description": "Data-driven insights and suggestions to maximize likes, shares, comments, and overall engagement."
},
{
"title": "🕒 Optimal Timing",
"description": "AI recommendations for the best times to post based on your audience's activity patterns."
},
{
"title": "🔍 Hashtag Intelligence",
"description": "Smart hashtag suggestions and trending topic analysis to increase your content's discoverability."
}
]
for idx, feature in enumerate(features):
with feature_cols[idx % 2]:
st.markdown(f"""
<div class="premium-card" style="min-height: 160px; cursor: default;">
<div class="card-glow"></div>
<div class="card-content">
<div class="card-title" style="margin-bottom: 0.8rem;">{feature['title']}</div>
<div class="card-description" style="margin-bottom: 0;">{feature['description']}</div>
</div>
<div class="card-shine"></div>
</div>
""", unsafe_allow_html=True)

View File

@@ -1,439 +0,0 @@
import streamlit as st
from lib.ai_seo_tools.seo_structured_data import ai_structured_data
from lib.ai_seo_tools.content_title_generator import ai_title_generator
from lib.ai_seo_tools.meta_desc_generator import metadesc_generator_main
from lib.ai_seo_tools.image_alt_text_generator import alt_text_gen
from lib.ai_seo_tools.opengraph_generator import og_tag_generator
from lib.ai_seo_tools.optimize_images_for_upload import main_img_optimizer
from lib.ai_seo_tools.google_pagespeed_insights import google_pagespeed_insights
from lib.ai_seo_tools.on_page_seo_analyzer import analyze_onpage_seo
from lib.ai_seo_tools.weburl_seo_checker import url_seo_checker
from lib.ai_marketing_tools.ai_backlinker.backlinking_ui_streamlit import backlinking_ui
from lib.ai_seo_tools.content_gap_analysis.ui import ContentGapAnalysisUI
from lib.ai_seo_tools.content_calendar.ui.dashboard import ContentCalendarDashboard
def render_content_gap_analysis():
"""Render the content gap analysis workflow interface."""
from lib.ai_seo_tools.content_gap_analysis.ui import ContentGapAnalysisUI
# Initialize and run the Content Gap Analysis UI
ui = ContentGapAnalysisUI()
ui.run()
def render_content_calendar():
"""Render the content calendar dashboard."""
import logging
import sys
from datetime import datetime
# Configure logging
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.StreamHandler(sys.stdout),
logging.FileHandler('content_calendar.log', mode='a')
]
)
logger = logging.getLogger('content_calendar')
try:
logger.info("Initializing Content Calendar Dashboard")
dashboard = ContentCalendarDashboard()
logger.info("Rendering Content Calendar Dashboard")
dashboard.render()
logger.info("Content Calendar Dashboard rendered successfully")
except Exception as e:
logger.error(f"Error rendering content calendar: {str(e)}", exc_info=True)
st.error(f"An error occurred while loading the content calendar: {str(e)}")
def render_seo_tools_dashboard():
"""Render a modern dashboard for SEO tools with improved UI and navigation."""
selected_section = st.session_state.get('seo_dashboard_section', 'combinations')
# Define card gradients at the top so it's available in all sections
card_gradients = {
"Content Optimization Suite": "linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)",
"Technical SEO Audit": "linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
"Image Optimization Suite": "linear-gradient(135deg, #f7971e 0%, #ffd200 100%)",
"Social Media Optimization": "linear-gradient(135deg, #f953c6 0%, #b91d73 100%)",
"Content Gap Analysis": "linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
"Content Calendar": "linear-gradient(135deg, #4CAF50 0%, #2196F3 100%)",
"Structured Data Generator": "linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)",
"Blog Title Generator": "linear-gradient(135deg, #2193b0 0%, #6dd5ed 100%)",
"Meta Description Generator": "linear-gradient(135deg, #f7971e 0%, #ffd200 100%)",
"Image Alt Text Generator": "linear-gradient(135deg, #f953c6 0%, #b91d73 100%)",
"OpenGraph Tags Generator": "linear-gradient(135deg, #f857a6 0%, #ff5858 100%)",
"Image Optimizer": "linear-gradient(135deg, #43cea2 0%, #185a9d 100%)",
"PageSpeed Insights": "linear-gradient(135deg, #ff9966 0%, #ff5e62 100%)",
"On-Page SEO Analyzer": "linear-gradient(135deg, #56ab2f 0%, #a8e063 100%)",
"URL SEO Checker": "linear-gradient(135deg, #3a7bd5 0%, #00d2ff 100%)",
"AI Backlinking Tool": "linear-gradient(135deg, #e96443 0%, #904e95 100%)"
}
# Navigation bar only (no dashboard title/description)
nav_cols = st.columns([1,1,1,1])
nav_labels = ["Tool Combos", "Advanced", "Individual", "About"]
nav_keys = ["combinations", "advanced", "individual", "about"]
for i, label in enumerate(nav_labels):
if nav_cols[i].button(label, key=f"nav_{label}"):
st.session_state['seo_dashboard_section'] = nav_keys[i]
selected_section = nav_keys[i]
st.markdown("<hr style='margin:1.5rem 0;'>", unsafe_allow_html=True)
# Define tool combinations for cross-tool analysis
tool_combinations = {
"Content Optimization Suite": {
"icon": "📊",
"description": "Comprehensive content optimization combining title generation, meta descriptions, and structured data.",
"tools": ["Blog Title Generator", "Meta Description Generator", "Structured Data Generator"],
"path": "content_optimization",
"color": "#4CAF50"
},
"Technical SEO Audit": {
"icon": "🔧",
"description": "Complete technical SEO analysis including page speed, on-page SEO, and URL structure.",
"tools": ["PageSpeed Insights", "On-Page SEO Analyzer", "URL SEO Checker"],
"path": "technical_audit",
"color": "#2196F3"
},
"Image Optimization Suite": {
"icon": "🖼️",
"description": "End-to-end image optimization with alt text generation and performance optimization.",
"tools": ["Image Alt Text Generator", "Image Optimizer"],
"path": "image_optimization",
"color": "#FF9800"
},
"Social Media Optimization": {
"icon": "📱",
"description": "Enhance social media presence with OpenGraph tags and backlink analysis.",
"tools": ["OpenGraph Tags Generator", "AI Backlinking Tool"],
"path": "social_optimization",
"color": "#9C27B0"
}
}
# Define individual SEO tools
seo_tools = {
"Structured Data Generator": {
"icon": "📋",
"description": "Generate structured data (Rich Snippets) to enhance your search results with additional information.",
"color": "#4CAF50",
"path": "structured_data",
"status": "active"
},
"Blog Title Generator": {
"icon": "✏️",
"description": "Create SEO-optimized blog titles that attract clicks and improve search rankings.",
"color": "#2196F3",
"path": "blog_title",
"status": "active"
},
"Meta Description Generator": {
"icon": "📝",
"description": "Generate compelling meta descriptions that improve click-through rates from search results.",
"color": "#FF9800",
"path": "meta_description",
"status": "active"
},
"Image Alt Text Generator": {
"icon": "🖼️",
"description": "Create descriptive alt text for images to improve accessibility and image SEO.",
"color": "#9C27B0",
"path": "alt_text",
"status": "active"
},
"OpenGraph Tags Generator": {
"icon": "📱",
"description": "Generate OpenGraph tags for better social media sharing and visibility.",
"color": "#F44336",
"path": "opengraph",
"status": "active"
},
"Image Optimizer": {
"icon": "📉",
"description": "Optimize and resize images for better website performance and SEO.",
"color": "#607D8B",
"path": "image_optimizer",
"status": "active"
},
"PageSpeed Insights": {
"icon": "",
"description": "Analyze your website's performance using Google PageSpeed Insights.",
"color": "#795548",
"path": "pagespeed",
"status": "active"
},
"On-Page SEO Analyzer": {
"icon": "🔍",
"description": "Analyze and optimize your webpage's SEO elements and content.",
"color": "#009688",
"path": "onpage_seo",
"status": "active"
},
"URL SEO Checker": {
"icon": "🌐",
"description": "Check the SEO health of specific URLs and get improvement suggestions.",
"color": "#3F51B5",
"path": "url_checker",
"status": "active"
},
"AI Backlinking Tool": {
"icon": "🔗",
"description": "Discover and analyze backlink opportunities using AI-powered insights.",
"color": "#E91E63",
"path": "backlinking",
"status": "active"
}
}
# --- Tool Combinations Section ---
if selected_section == 'combinations':
combo_cols = st.columns(2)
for idx, (combo_name, details) in enumerate(tool_combinations.items()):
gradient = card_gradients.get(combo_name, "linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%)")
with combo_cols[idx % 2]:
st.markdown(f"""
<div class="seo-card" style="background: {gradient}; position: relative; overflow: hidden;">
<div class="seo-card-overlay"></div>
<div class="seo-icon">{details['icon']}</div>
<div class="seo-title">{combo_name}</div>
<div class="seo-description">{details['description']}</div>
<div>
{''.join([f'<span class="tool-badge">{tool}</span>' for tool in details['tools']])}
</div>
</div>
""", unsafe_allow_html=True)
if st.button(f"Launch {combo_name}", key=f"combo_{combo_name}", use_container_width=True):
st.query_params["tool"] = details["path"]
st.rerun()
# --- Advanced Features Section ---
elif selected_section == 'advanced':
adv_cols = st.columns(2)
adv_features = [
{
"name": "Content Gap Analysis",
"icon": "🎯",
"description": "Identify content opportunities and optimize your content strategy with AI-powered insights.",
"badges": ["Website Analysis", "Competitor Research", "Keyword Opportunities", "AI Recommendations"],
"gradient": card_gradients["Content Gap Analysis"],
"button": "Start Content Gap Analysis",
"key": "content_gap_analysis",
"path": "content_gap_analysis"
},
{
"name": "Content Calendar",
"icon": "📅",
"description": "Plan, schedule, and manage your content strategy with our AI-powered content calendar.",
"badges": ["Content Planning", "Scheduling", "Performance Tracking", "AI Insights"],
"gradient": card_gradients["Content Calendar"],
"button": "Open Content Calendar",
"key": "content_calendar",
"path": "content_calendar"
}
]
for idx, feature in enumerate(adv_features):
with adv_cols[idx % 2]:
st.markdown(f"""
<div class="seo-card" style="background: {feature['gradient']}; position: relative; overflow: hidden;">
<div class="seo-card-overlay"></div>
<div class="seo-icon">{feature['icon']}</div>
<div class="seo-title">{feature['name']}</div>
<div class="seo-description">{feature['description']}</div>
<div>
{''.join([f'<span class="tool-badge">{badge}</span>' for badge in feature['badges']])}
</div>
</div>
""", unsafe_allow_html=True)
if st.button(feature['button'], key=feature['key'], use_container_width=True):
st.query_params["tool"] = feature["path"]
st.rerun()
# --- Individual Tools Section ---
elif selected_section == 'individual':
cols = st.columns(3)
for idx, (tool_name, details) in enumerate(seo_tools.items()):
gradient = card_gradients.get(tool_name, "linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%)")
with cols[idx % 3]:
st.markdown(f"""
<div class="seo-card" style="background: {gradient}; position: relative; overflow: hidden;">
<div class="seo-card-overlay"></div>
<div class="seo-icon">{details['icon']}</div>
<div class="seo-title">{tool_name}</div>
<div class="seo-description">{details['description']}</div>
</div>
""", unsafe_allow_html=True)
if st.button(f"Use {tool_name}", key=f"btn_{tool_name}", use_container_width=True):
st.query_params["tool"] = details["path"]
st.rerun()
# --- About Section ---
elif selected_section == 'about':
st.markdown("""
<div style='text-align: center; margin: 2rem 0;'>
<h2>About This Dashboard</h2>
<p style='color: #666;'>This dashboard brings together powerful AI-driven SEO tools and workflows to help you optimize your website and content strategy. Use the navigation above to explore combinations, advanced features, or individual tools.</p>
</div>
""", unsafe_allow_html=True)
st.markdown("""
<style>
.seo-card {
border-radius: 14px;
padding: 24px;
margin-bottom: 24px;
box-shadow: 0 4px 16px rgba(44, 62, 80, 0.10), 0 1.5px 4px rgba(44,62,80,0.06);
transition: transform 0.2s cubic-bezier(.4,2,.6,1), box-shadow 0.2s;
height: 100%;
border: 1.5px solid #e3e8ee;
position: relative;
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.seo-card-overlay {
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(255,255,255,0.72);
z-index: 1;
pointer-events: none;
border-radius: 14px;
box-shadow: 0 2px 8px rgba(44,62,80,0.08);
}
.seo-card:hover {
transform: translateY(-6px) scale(1.025);
box-shadow: 0 8px 32px rgba(44, 62, 80, 0.18), 0 2px 8px rgba(44,62,80,0.10);
border-color: #4CAF50;
}
.seo-icon {
font-size: 2.7rem;
margin-bottom: 18px;
z-index: 2;
position: relative;
text-shadow: 0 2px 8px rgba(44,62,80,0.10);
}
.seo-title {
font-size: 1.25rem;
font-weight: 800;
margin-bottom: 12px;
color: #222b45;
z-index: 2;
position: relative;
text-shadow: 0 2px 8px rgba(44,62,80,0.10);
letter-spacing: 0.01em;
}
.seo-description {
color: #34495e;
font-size: 1.08rem;
margin-bottom: 15px;
z-index: 2;
position: relative;
text-align: center;
line-height: 1.5;
text-shadow: 0 1px 4px rgba(44,62,80,0.08);
}
.tool-badge {
display: inline-block;
padding: 4px 12px;
border-radius: 12px;
font-size: 0.9rem;
margin-right: 8px;
margin-bottom: 8px;
background: rgba(255, 255, 255, 0.95);
color: #2196F3;
font-weight: 600;
border: 1px solid #e3e8ee;
}
</style>
""", unsafe_allow_html=True)
def ai_seo_tools():
"""
A collection of AI-powered SEO tools for content creators, providing various options
such as generating structured data, optimizing images, checking page speed,
and analyzing on-page SEO.
"""
# Check if a specific tool is selected
selected_tool = st.query_params.get("tool")
if selected_tool:
# Map tool paths to their respective functions
tool_functions = {
# Individual tools
"structured_data": ai_structured_data,
"blog_title": ai_title_generator,
"meta_description": metadesc_generator_main,
"alt_text": alt_text_gen,
"opengraph": og_tag_generator,
"image_optimizer": main_img_optimizer,
"pagespeed": google_pagespeed_insights,
"onpage_seo": analyze_onpage_seo,
"url_checker": url_seo_checker,
"backlinking": backlinking_ui,
# Tool combinations
"content_optimization": lambda: run_tool_combination([
ai_title_generator,
metadesc_generator_main,
ai_structured_data
], "Content Optimization Suite"),
"technical_audit": lambda: run_tool_combination([
google_pagespeed_insights,
analyze_onpage_seo,
url_seo_checker
], "Technical SEO Audit"),
"image_optimization": lambda: run_tool_combination([
alt_text_gen,
main_img_optimizer
], "Image Optimization Suite"),
"social_optimization": lambda: run_tool_combination([
og_tag_generator,
backlinking_ui
], "Social Media Optimization"),
# Add Content Gap Analysis and Content Calendar
"content_gap_analysis": render_content_gap_analysis,
"content_calendar": render_content_calendar
}
if selected_tool in tool_functions:
# Clear any existing content
st.empty()
# Execute the selected tool's function
tool_functions[selected_tool]()
else:
st.error(f"Invalid tool selected: {selected_tool}")
render_seo_tools_dashboard()
else:
# Show the dashboard if no tool is selected
render_seo_tools_dashboard()
def run_tool_combination(tools, combination_name):
"""Run a combination of tools and provide cross-tool analysis."""
st.markdown(f"# {combination_name}")
st.markdown("Running comprehensive analysis...")
# Create tabs for each tool in the combination
tabs = st.tabs([f"Step {i+1}" for i in range(len(tools))])
# Run each tool in its own tab
for i, (tab, tool) in enumerate(zip(tabs, tools)):
with tab:
st.markdown(f"### Step {i+1}")
tool()
# Add cross-tool analysis section
st.markdown("## 📊 Cross-Tool Analysis")
st.markdown("Analyzing results across all tools...")
# Add recommendations based on combined results
st.markdown("## 💡 Recommendations")
st.markdown("Based on the combined analysis, here are the key recommendations:")
# Add a button to export the complete analysis
if st.button("📥 Export Complete Analysis", use_container_width=True):
st.info("Analysis export functionality coming soon!")

View File

@@ -1,438 +0,0 @@
import streamlit as st
from loguru import logger
import asyncio
from lib.web_crawlers.async_web_crawler import AsyncWebCrawlerService
from lib.personalization.style_analyzer import StyleAnalyzer
import sys
# Configure logger
logger.remove() # Remove default handler
logger.add(
"logs/settings_page.log",
rotation="500 MB",
retention="10 days",
level="DEBUG",
format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}",
backtrace=True,
diagnose=True
)
logger.add(
sys.stdout,
level="INFO",
format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{message}</cyan>"
)
def display_style_analysis(analysis_results: dict):
"""Display the style analysis results in a structured format."""
try:
# Writing Style Section
st.markdown("### 🎨 Writing Style Analysis")
writing_style = analysis_results.get("writing_style", {})
writing_style_content = f"""
<ul>
<li><strong>Tone:</strong> {writing_style.get("tone", "N/A")}</li>
<li><strong>Voice:</strong> {writing_style.get("voice", "N/A")}</li>
<li><strong>Complexity:</strong> {writing_style.get("complexity", "N/A")}</li>
<li><strong>Engagement Level:</strong> {writing_style.get("engagement_level", "N/A")}</li>
</ul>
"""
st.markdown(writing_style_content, unsafe_allow_html=True)
# Content Characteristics Section
content_chars = analysis_results.get("content_characteristics", {})
content_chars_content = f"""
<ul>
<li><strong>Sentence Structure:</strong> {content_chars.get("sentence_structure", "N/A")}</li>
<li><strong>Vocabulary Level:</strong> {content_chars.get("vocabulary_level", "N/A")}</li>
<li><strong>Paragraph Organization:</strong> {content_chars.get("paragraph_organization", "N/A")}</li>
<li><strong>Content Flow:</strong> {content_chars.get("content_flow", "N/A")}</li>
</ul>
"""
st.markdown(content_chars_content, unsafe_allow_html=True)
# Target Audience Section
target_audience = analysis_results.get("target_audience", {})
target_audience_content = f"""
<ul>
<li><strong>Demographics:</strong> {', '.join(target_audience.get("demographics", ["N/A"]))}</li>
<li><strong>Expertise Level:</strong> {target_audience.get("expertise_level", "N/A")}</li>
<li><strong>Industry Focus:</strong> {target_audience.get("industry_focus", "N/A")}</li>
<li><strong>Geographic Focus:</strong> {target_audience.get("geographic_focus", "N/A")}</li>
</ul>
"""
st.markdown(target_audience_content, unsafe_allow_html=True)
# Content Type Section
content_type = analysis_results.get("content_type", {})
content_type_content = f"""
<ul>
<li><strong>Primary Type:</strong> {content_type.get("primary_type", "N/A")}</li>
<li><strong>Secondary Types:</strong> {', '.join(content_type.get("secondary_types", ["N/A"]))}</li>
<li><strong>Purpose:</strong> {content_type.get("purpose", "N/A")}</li>
<li><strong>Call to Action:</strong> {content_type.get("call_to_action", "N/A")}</li>
</ul>
"""
st.markdown(content_type_content, unsafe_allow_html=True)
# Recommended Settings Section
recommended = analysis_results.get("recommended_settings", {})
recommended_content = f"""
<ul>
<li><strong>Writing Tone:</strong> {recommended.get("writing_tone", "N/A")}</li>
<li><strong>Target Audience:</strong> {recommended.get("target_audience", "N/A")}</li>
<li><strong>Content Type:</strong> {recommended.get("content_type", "N/A")}</li>
<li><strong>Creativity Level:</strong> {recommended.get("creativity_level", "N/A")}</li>
<li><strong>Geographic Location:</strong> {recommended.get("geographic_location", "N/A")}</li>
</ul>
"""
st.markdown(recommended_content, unsafe_allow_html=True)
except Exception as e:
logger.error(f"Error displaying style analysis: {str(e)}")
st.error(f"Error displaying analysis results: {str(e)}")
def render_settings_page():
"""Renders the settings page with all configuration options in tabs"""
st.title("🛠️ Settings & Configuration")
# Create tabs for different settings categories
tabs = st.tabs([
"👷 Content",
"🩻 Images",
"🤖 LLM",
"🕵️ Search",
"🎨 AI Personalization"
])
# Content Settings Tab
with tabs[0]:
st.header("Content Personalization")
blog_length = st.text_input(
"**Content Length (words)**",
value="2000",
key="settings_blog_length",
help="Approximate word count for blogs. Note: Actual length may vary based on GPT provider and max token count."
)
blog_tone_options = ["Casual", "Professional", "How-to", "Beginner", "Research", "Programming", "Social Media", "Customize"]
blog_tone = st.selectbox(
"**Content Tone**",
options=blog_tone_options,
key="settings_blog_tone",
help="Select the desired tone for the blog content."
)
if blog_tone == "Customize":
custom_tone = st.text_input(
"Enter the tone of your content",
key="settings_custom_tone",
help="Specify the tone of your content."
)
if custom_tone:
blog_tone = custom_tone
else:
st.warning("Please specify the tone of your content.")
blog_demographic_options = ["Professional", "Gen-Z", "Tech-savvy", "Student", "Digital Marketing", "Customize"]
blog_demographic = st.selectbox(
"**Target Audience**",
options=blog_demographic_options,
key="settings_blog_demographic",
help="Select the primary audience for the blog content."
)
blog_type = st.selectbox(
"**Content Type**",
options=["Informational", "Commercial", "Company", "News", "Finance", "Competitor", "Programming", "Scholar"],
key="settings_blog_type",
help="Select the category that best describes the blog content."
)
blog_language = st.selectbox(
"**Content Language**",
options=["English", "Spanish", "German", "Chinese", "Arabic", "Nepali", "Hindi", "Hindustani", "Customize"],
key="settings_blog_language",
help="Select the language in which the blog will be written."
)
blog_output_format = st.selectbox(
"**Content Output Format**",
options=["markdown", "HTML", "plaintext"],
key="settings_blog_output_format",
help="Select the format for the blog output."
)
# Images Settings Tab
with tabs[1]:
st.header("Images Personalization")
image_generation_model = st.selectbox(
"**Image Generation Model**",
options=["stable-diffusion", "dalle2", "dalle3"],
key="settings_image_model",
help="Select the model to generate images for the blog."
)
number_of_blog_images = st.number_input(
"**Number of Blog Images**",
value=1,
min_value=1,
max_value=10,
key="settings_number_of_images",
help="Specify the number of images to include in the blog."
)
# LLM Settings Tab
with tabs[2]:
st.header("LLM Personalization")
gpt_provider = st.selectbox(
"**GPT Provider**",
options=["google", "openai", "minstral"],
key="settings_gpt_provider",
help="Select the provider for the GPT model."
)
model = st.text_input(
"**Model**",
value="gemini-1.5-flash-latest",
key="settings_model",
help="Specify the model version to use from the selected provider."
)
col1, col2 = st.columns(2)
with col1:
temperature = st.slider(
"Temperature",
min_value=0.1,
max_value=1.0,
value=0.7,
step=0.1,
key="settings_temperature",
help="Controls the creativity level of the generated text."
)
max_tokens = st.selectbox(
"Max Tokens",
options=[500, 1000, 2000, 4000, 16000, 32000, 64000],
index=3,
key="settings_max_tokens",
help="Maximum length of the output sequence."
)
with col2:
top_p = st.slider(
"Top-p",
min_value=0.0,
max_value=1.0,
value=0.9,
step=0.1,
key="settings_top_p",
help="Controls diversity in text generation."
)
frequency_penalty = st.slider(
"Frequency Penalty",
min_value=0.0,
max_value=2.0,
value=1.0,
step=0.1,
key="settings_frequency_penalty",
help="Reduces word repetition in output."
)
# Search Settings Tab
with tabs[3]:
st.header("Search Engine Personalization")
geographic_location = st.selectbox(
"**Geographic Location**",
options=["us", "in", "fr", "cn"],
key="settings_geographic_location",
help="Select the geographic location for tailoring search results."
)
search_language = st.selectbox(
"**Search Language**",
options=["en", "zn-cn", "de", "hi"],
key="settings_search_language",
help="Select the language for the search results."
)
number_of_results = st.number_input(
"**Number of Results**",
value=10,
min_value=1,
max_value=20,
key="settings_number_of_results",
help="Specify the number of search results to retrieve."
)
time_range = st.selectbox(
"**Time Range**",
options=["anytime", "past day", "past week", "past month", "past year"],
key="settings_time_range",
help="Select the time range for filtering search results."
)
include_domains = st.text_input(
"**Include Domains**",
value="",
key="settings_include_domains",
help="List specific domains to include in search results (comma-separated)."
)
similar_url = st.text_input(
"**Similar URL**",
value="",
key="settings_similar_url",
help="Provide a URL to find similar results."
)
# AI Personalization Tab
with tabs[4]:
st.header("🎨 AI Style Analysis")
st.markdown("""
<div style='background-color: rgba(255, 255, 255, 0.1); padding: 20px; border-radius: 10px; margin-bottom: 20px;'>
<p>Enter a website URL or provide content samples to analyze your writing style and get personalized recommendations.</p>
</div>
""", unsafe_allow_html=True)
# Create two columns for the layout
col1, col2 = st.columns([2, 1])
with col1:
# Website URL input
st.markdown("### Website URL")
url = st.text_input(
"Enter your website URL",
placeholder="https://example.com",
key="settings_website_url",
help="Provide your website URL to analyze your content style. Leave empty if you want to provide written samples instead."
)
# Alternative: Written samples
if not url:
st.markdown("### Written Samples")
st.markdown("""
<div style='background-color: rgba(255, 255, 255, 0.1); padding: 20px; border-radius: 10px; margin-bottom: 20px;'>
<p>No website URL? No problem! You can provide written samples of your content instead.</p>
<p>Share your best articles, blog posts, or any content that represents your writing style.</p>
</div>
""", unsafe_allow_html=True)
samples = st.text_area(
"Paste your content samples here",
key="settings_content_samples",
help="Paste 2-3 samples of your best content. This helps ALwrity understand your writing style."
)
# ALwrity Style button
st.markdown("<div style='height: 20px'></div>", unsafe_allow_html=True)
if st.button("🎨 Analyze Style", use_container_width=True, key="settings_analyze_style"):
if url:
with st.status("Starting style analysis...", expanded=True) as status:
try:
# Step 1: Initialize crawler
status.update(label="Step 1/4: Initializing web crawler...", state="running")
crawler_service = AsyncWebCrawlerService()
# Step 2: Crawl website
status.update(label="Step 2/4: Crawling website content...", state="running")
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
result = loop.run_until_complete(crawler_service.crawl_website(url))
loop.close()
if result.get('success', False):
content = result.get('content', {})
# Step 3: Initialize style analyzer
status.update(label="Step 3/4: Analyzing content style...", state="running")
style_analyzer = StyleAnalyzer()
# Step 4: Perform style analysis
status.update(label="Step 4/4: Generating style recommendations...", state="running")
style_analysis = style_analyzer.analyze_content_style(content)
if style_analysis.get('error'):
status.update(label="Analysis failed", state="error")
st.error(f"Style analysis failed: {style_analysis['error']}")
else:
status.update(label="Analysis complete!", state="complete")
# Display style analysis results
display_style_analysis(style_analysis)
# Display original content in tabs
tab1, tab2, tab3 = st.tabs(["Content", "Metadata", "Links"])
with tab1:
st.markdown("### Main Content")
st.markdown(content.get('main_content', 'No content found'))
with tab2:
st.markdown("### Metadata")
st.markdown(f"""
**Title:** {content.get('title', 'No title found')}
**Description:** {content.get('description', 'No description found')}
**Meta Tags:**
{content.get('meta_tags', {})}
""")
with tab3:
st.markdown("### Links")
for link in content.get('links', []):
st.markdown(f"- [{link.get('text', '')}]({link.get('href', '')})")
else:
status.update(label="Crawling failed", state="error")
st.error("Failed to crawl the website. Please check the URL and try again.")
except Exception as e:
status.update(label="Analysis failed", state="error")
st.error(f"An error occurred during analysis: {str(e)}")
elif samples:
with st.status("Starting style analysis...", expanded=True) as status:
try:
# Initialize style analyzer
status.update(label="Analyzing content style...", state="running")
style_analyzer = StyleAnalyzer()
# Perform style analysis
style_analysis = style_analyzer.analyze_content_style({"main_content": samples})
if style_analysis.get('error'):
status.update(label="Analysis failed", state="error")
st.error(f"Style analysis failed: {style_analysis['error']}")
else:
status.update(label="Analysis complete!", state="complete")
# Display style analysis results
display_style_analysis(style_analysis)
except Exception as e:
status.update(label="Analysis failed", state="error")
st.error(f"An error occurred during analysis: {str(e)}")
else:
st.warning("Please provide either a website URL or content samples to analyze.")
# Save Settings Button
if st.button("💾 Save Settings", type="primary", use_container_width=True, key="settings_save_button"):
# Save all settings to session state
st.session_state.update({
'blog_length': blog_length,
'blog_tone': blog_tone,
'blog_demographic': blog_demographic,
'blog_type': blog_type,
'blog_language': blog_language,
'blog_output_format': blog_output_format,
'image_generation_model': image_generation_model,
'number_of_blog_images': number_of_blog_images,
'gpt_provider': gpt_provider,
'model': model,
'temperature': temperature,
'top_p': top_p,
'max_tokens': max_tokens,
'frequency_penalty': frequency_penalty,
'geographic_location': geographic_location,
'search_language': search_language,
'number_of_results': number_of_results,
'time_range': time_range,
'include_domains': include_domains,
'similar_url': similar_url
})
st.success("✅ Settings saved successfully!")

View File

@@ -8,8 +8,9 @@ import streamlit as st
from lib.utils.file_processor import load_image
from lib.utils.content_generators import content_planning_tools
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
from lib.alwrity_ui.seo_tools_dashboard import ai_seo_tools
from lib.alwrity_ui.settings_page import render_settings_page
from lib.alwrity_ui.navigation_styles import apply_navigation_styles, apply_compact_layout
from loguru import logger
# Import social media writer functions
@@ -20,378 +21,13 @@ from lib.ai_writers.insta_ai_writer import insta_writer
from lib.ai_writers.youtube_writers.youtube_ai_writer import youtube_main_menu
from lib.ai_writers.ai_writer_dashboard import get_ai_writers, list_ai_writers
from lib.chatbot_custom.enhanced_alwrity_chatbot import run_enhanced_chatbot
from lib.alwrity_ui.social_media_dashboard import render_social_tools_dashboard
def render_social_tools_dashboard():
"""Render a modern dashboard for social media tools."""
st.markdown("""
<style>
.social-card {
background: white;
border-radius: 10px;
padding: 20px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
transition: transform 0.3s ease;
height: 100%;
}
.social-card:hover {
transform: translateY(-5px);
}
.social-icon {
font-size: 2.5rem;
margin-bottom: 15px;
}
.social-title {
font-size: 1.2rem;
font-weight: 600;
margin-bottom: 10px;
}
.social-description {
color: #666;
font-size: 0.9rem;
margin-bottom: 15px;
}
.social-button {
width: 100%;
padding: 8px 16px;
border-radius: 5px;
border: none;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
}
</style>
""", unsafe_allow_html=True)
# Define social tools with their details and paths
social_tools = {
"Facebook": {
"icon": "📘",
"description": "Create engaging Facebook posts and manage your content strategy",
"color": "#4267B2",
"path": "facebook"
},
"LinkedIn": {
"icon": "💼",
"description": "Generate professional LinkedIn content and optimize your profile",
"color": "#0077B5",
"path": "linkedin"
},
"Twitter": {
"icon": "🐦",
"description": "Craft viral tweets and manage your Twitter presence",
"color": "#1DA1F2",
"path": "twitter"
},
"Instagram": {
"icon": "📸",
"description": "Create Instagram captions and plan your visual content",
"color": "#E1306C",
"path": "instagram"
},
"YouTube": {
"icon": "🎥",
"description": "Generate video scripts and optimize your YouTube content",
"color": "#FF0000",
"path": "youtube"
}
}
# Create a grid of cards
cols = st.columns(3)
for idx, (platform, details) in enumerate(social_tools.items()):
with cols[idx % 3]:
st.markdown(f"""
<div class="social-card">
<div class="social-icon">{details['icon']}</div>
<div class="social-title">{platform}</div>
<div class="social-description">{details['description']}</div>
</div>
""", unsafe_allow_html=True)
if st.button(f"Open {platform}", key=f"btn_{platform}",
help=f"Launch {platform} tools",
use_container_width=True):
# Set query parameters to redirect to the specific tool
st.query_params["tool"] = details["path"]
st.rerun()
def setup_ui():
"""Set up the UI with custom styling."""
# Add custom CSS
st.markdown("""
<style>
/* Main app styling */
.stApp {
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 */
.stButton > button {
border-radius: 8px;
font-weight: 500;
transition: all 0.3s ease;
margin-bottom: 0.25rem; /* Reduced from 0.5rem */
}
.stButton > button:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}
/* Input field styling */
.stTextInput > div > div > input {
border-radius: 8px;
border: 1px solid rgba(0,0,0,0.1);
padding: 0.5rem 1rem;
}
/* Checkbox styling */
.stCheckbox > label {
font-weight: 500;
}
/* Expander styling */
.streamlit-expanderHeader {
font-weight: 500;
color: #2c3e50;
margin-bottom: 0.5rem;
}
/* Success message styling */
.stSuccess {
background: linear-gradient(135deg, #43c6ac 0%, #191654 100%);
padding: 0.75rem;
border-radius: 8px;
color: white;
margin-bottom: 1rem;
}
/* Error message styling */
.stError {
background: linear-gradient(135deg, #ff6b6b 0%, #ff8e8e 100%);
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: 0.5rem 0;
}
.nav-button {
width: 100%;
text-align: left;
padding: 0.5rem 1rem;
background: transparent;
border: none;
color: #2c3e50;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
margin: 0.2rem 0;
border-radius: 4px;
}
.nav-button:hover {
background: rgba(0,0,0,0.05);
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)
# Apply navigation-specific styling
apply_navigation_styles()
def setup_alwrity_ui():
@@ -475,14 +111,8 @@ def setup_alwrity_ui():
render_social_tools_dashboard()
else:
# Show the dashboard if no tool 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}")
apply_compact_layout()
logger.info(f"{nav_items[st.session_state.active_tab][0]} {st.session_state.active_tab}")
render_social_tools_dashboard()
else:
# Handle other tabs as before
@@ -511,15 +141,8 @@ def setup_alwrity_ui():
logger.info("No writer selected, showing dashboard")
get_ai_writers()
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}")
apply_compact_layout()
logger.info(f"{nav_items[st.session_state.active_tab][0]} {st.session_state.active_tab}")
nav_items[st.session_state.active_tab][1]()
logger.info("Finished setting up ALwrity UI")