AI writers, SEO, Social media, Settings, Dashboard UI styling changes
This commit is contained in:
@@ -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!
|
||||
@@ -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! 🎯**
|
||||
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -344,4 +344,4 @@ def main():
|
||||
print("your content creation process!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
@@ -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
|
||||
510
lib/alwrity_ui/dashboard_styles.py
Normal file
510
lib/alwrity_ui/dashboard_styles.py
Normal 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
|
||||
)
|
||||
331
lib/alwrity_ui/navigation_styles.py
Normal file
331
lib/alwrity_ui/navigation_styles.py
Normal 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)
|
||||
293
lib/alwrity_ui/seo_tools_dashboard.py
Normal file
293
lib/alwrity_ui/seo_tools_dashboard.py
Normal 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!")
|
||||
973
lib/alwrity_ui/settings_page.py
Normal file
973
lib/alwrity_ui/settings_page.py
Normal 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)
|
||||
116
lib/alwrity_ui/social_media_dashboard.py
Normal file
116
lib/alwrity_ui/social_media_dashboard.py
Normal 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)
|
||||
@@ -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!")
|
||||
@@ -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!")
|
||||
@@ -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")
|
||||
Reference in New Issue
Block a user