AI twitter and linkedin writers changes.
This commit is contained in:
347
lib/ai_writers/linkedin_writer/README.md
Normal file
347
lib/ai_writers/linkedin_writer/README.md
Normal file
@@ -0,0 +1,347 @@
|
|||||||
|
# LinkedIn AI Writer
|
||||||
|
|
||||||
|
A comprehensive suite of AI-powered tools for generating professional LinkedIn content.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
LinkedIn AI Writer is a powerful tool designed to help professionals, businesses, and content creators generate high-quality LinkedIn content. It leverages advanced AI models to create engaging posts, articles, carousels, video scripts, and more, all optimized for LinkedIn's platform.
|
||||||
|
|
||||||
|
## Tools Status
|
||||||
|
|
||||||
|
| Tool | Status | Category |
|
||||||
|
|------|--------|----------|
|
||||||
|
| LinkedIn Post Generator | ✅ Active | Content Creation |
|
||||||
|
| LinkedIn Article Generator | ✅ Active | Content Creation |
|
||||||
|
| LinkedIn Carousel Post Generator | ✅ Active | Content Creation |
|
||||||
|
| LinkedIn Video Script Generator | ✅ Active | Content Creation |
|
||||||
|
| LinkedIn Poll Generator | ✅ Active | Content Creation |
|
||||||
|
| LinkedIn Comment Response Generator | ✅ Active | Engagement |
|
||||||
|
| LinkedIn Profile Optimizer | ✅ Active | Profile & Personal Branding |
|
||||||
|
| LinkedIn Company Page Content Generator | ✅ Active | Business & Marketing |
|
||||||
|
| LinkedIn Newsletter Generator | 🔄 Coming Soon | Business & Marketing |
|
||||||
|
| LinkedIn Job Description Generator | 🔄 Coming Soon | Business & Marketing |
|
||||||
|
| LinkedIn Sales Navigator Content Generator | 🔄 Coming Soon | Sales & Networking |
|
||||||
|
| LinkedIn InMail Generator | 🔄 Coming Soon | Sales & Networking |
|
||||||
|
| LinkedIn Learning Course Description Generator | 🔄 Coming Soon | Learning & Education |
|
||||||
|
| LinkedIn Event Description Generator | 🔄 Coming Soon | Learning & Education |
|
||||||
|
| LinkedIn Group Post Generator | 🔄 Coming Soon | Community & Engagement |
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
### Content Creation Tools
|
||||||
|
|
||||||
|
#### LinkedIn Post Generator
|
||||||
|
- **Status**: Active
|
||||||
|
- **Description**: Create engaging, professional posts that drive engagement and establish thought leadership.
|
||||||
|
- **Features**:
|
||||||
|
- Professional tone customization
|
||||||
|
- Industry-specific terminology
|
||||||
|
- Hashtag optimization
|
||||||
|
- Formatting options
|
||||||
|
- Character count optimization
|
||||||
|
- Call-to-action suggestions
|
||||||
|
- Engagement prediction
|
||||||
|
- Visual content recommendations
|
||||||
|
- Poll creation
|
||||||
|
- Best posting time suggestions
|
||||||
|
- Research-backed content
|
||||||
|
- Reference tracking
|
||||||
|
|
||||||
|
#### LinkedIn Article Generator
|
||||||
|
- **Status**: Active
|
||||||
|
- **Description**: Generate long-form professional articles that showcase expertise and drive traffic.
|
||||||
|
- **Features**:
|
||||||
|
- Topic research and outline generation
|
||||||
|
- SEO optimization for LinkedIn articles
|
||||||
|
- Professional writing style adaptation
|
||||||
|
- Section structuring
|
||||||
|
- Citation and reference formatting
|
||||||
|
- Image placement suggestions
|
||||||
|
- Headline optimization
|
||||||
|
- Meta description generation
|
||||||
|
- Reading time estimation
|
||||||
|
- Internal linking suggestions
|
||||||
|
- Multiple research sources (Metaphor, Google, Tavily)
|
||||||
|
- AI-generated section images
|
||||||
|
|
||||||
|
#### LinkedIn Carousel Post Generator
|
||||||
|
- **Status**: Active
|
||||||
|
- **Description**: Create engaging carousel posts that showcase information in a visually appealing way.
|
||||||
|
- **Features**:
|
||||||
|
- Slide content generation
|
||||||
|
- Visual hierarchy optimization
|
||||||
|
- Story arc development
|
||||||
|
- Call-to-action placement
|
||||||
|
- Brand consistency maintenance
|
||||||
|
- Engagement element integration
|
||||||
|
- Professional design suggestions
|
||||||
|
- Content distribution strategy
|
||||||
|
- Analytics integration
|
||||||
|
- A/B testing variations
|
||||||
|
|
||||||
|
#### LinkedIn Video Script Generator
|
||||||
|
- **Status**: Active
|
||||||
|
- **Description**: Create scripts for LinkedIn videos that drive engagement.
|
||||||
|
- **Features**:
|
||||||
|
- Hook generation
|
||||||
|
- Story structure development
|
||||||
|
- Professional speaking points
|
||||||
|
- Visual cue suggestions
|
||||||
|
- Call-to-action optimization
|
||||||
|
- Engagement prompt integration
|
||||||
|
- Caption generation
|
||||||
|
- Thumbnail text suggestions
|
||||||
|
- Video description optimization
|
||||||
|
- Hashtag strategy
|
||||||
|
|
||||||
|
#### LinkedIn Poll Generator
|
||||||
|
- **Status**: Active
|
||||||
|
- **Description**: Create engaging polls that drive interaction and gather insights.
|
||||||
|
- **Features**:
|
||||||
|
- Question formulation optimization
|
||||||
|
- Option generation based on topic
|
||||||
|
- Industry-specific poll templates
|
||||||
|
- Engagement prediction
|
||||||
|
- Result analysis suggestions
|
||||||
|
- Follow-up content recommendations
|
||||||
|
- Trending topic integration
|
||||||
|
- Professional tone maintenance
|
||||||
|
- Data visualization suggestions
|
||||||
|
- Poll scheduling optimization
|
||||||
|
|
||||||
|
### Engagement Tools
|
||||||
|
|
||||||
|
#### LinkedIn Comment Response Generator
|
||||||
|
- **Status**: Active
|
||||||
|
- **Description**: Generate professional and engaging responses to LinkedIn comments with AI-powered analysis and optimization.
|
||||||
|
- **Features**:
|
||||||
|
- Comment analysis and categorization
|
||||||
|
- Multiple response types (general, disagreement, value-add)
|
||||||
|
- Brand voice customization
|
||||||
|
- Engagement goal targeting
|
||||||
|
- Resource suggestion generation
|
||||||
|
- Follow-up question generation
|
||||||
|
- Tone optimization
|
||||||
|
- Response strategy recommendations
|
||||||
|
- Context-aware responses
|
||||||
|
- Professional formatting
|
||||||
|
|
||||||
|
### Profile & Personal Branding Tools
|
||||||
|
|
||||||
|
#### LinkedIn Profile Optimizer
|
||||||
|
- **Status**: Active
|
||||||
|
- **Description**: Enhance LinkedIn profiles to improve visibility and professional appeal.
|
||||||
|
- **Features**:
|
||||||
|
- Headline optimization
|
||||||
|
- About section generation
|
||||||
|
- Experience description enhancement
|
||||||
|
- Skills recommendation
|
||||||
|
- Project highlight creation
|
||||||
|
- Endorsement request generation
|
||||||
|
- Profile strength analysis
|
||||||
|
- Keyword optimization
|
||||||
|
- Professional summary generation
|
||||||
|
- Custom URL suggestions
|
||||||
|
|
||||||
|
### Business & Marketing Tools
|
||||||
|
|
||||||
|
#### LinkedIn Company Page Content Generator
|
||||||
|
- **Status**: Active
|
||||||
|
- **Description**: Create content for company pages that builds brand awareness and engagement.
|
||||||
|
- **Features**:
|
||||||
|
- Company profile optimization
|
||||||
|
- Company culture post generation
|
||||||
|
- Product/service announcement templates
|
||||||
|
- Employee spotlight content
|
||||||
|
- Company milestone celebrations
|
||||||
|
- Industry insights sharing
|
||||||
|
- Event promotion content
|
||||||
|
- Job posting templates
|
||||||
|
- Company news updates
|
||||||
|
- Brand voice consistency
|
||||||
|
- Engagement metrics optimization
|
||||||
|
|
||||||
|
#### LinkedIn Newsletter Generator
|
||||||
|
- **Status**: Coming Soon
|
||||||
|
- **Description**: Create professional newsletters that establish thought leadership and drive engagement.
|
||||||
|
- **Features**:
|
||||||
|
- Newsletter structure templates
|
||||||
|
- Topic clustering and organization
|
||||||
|
- Professional introduction and conclusion
|
||||||
|
- Industry trend analysis integration
|
||||||
|
- Expert quote suggestions
|
||||||
|
- Visual content recommendations
|
||||||
|
- Call-to-action optimization
|
||||||
|
- Subscriber engagement prompts
|
||||||
|
- Consistency maintenance
|
||||||
|
- Analytics integration suggestions
|
||||||
|
|
||||||
|
#### LinkedIn Job Description Generator
|
||||||
|
- **Status**: Coming Soon
|
||||||
|
- **Description**: Create compelling job descriptions that attract qualified candidates.
|
||||||
|
- **Features**:
|
||||||
|
- Role-specific templates
|
||||||
|
- Skills and qualifications optimization
|
||||||
|
- Company culture integration
|
||||||
|
- Benefits and perks highlighting
|
||||||
|
- Inclusive language checker
|
||||||
|
- Keyword optimization
|
||||||
|
- Application process clarity
|
||||||
|
- Remote/hybrid work policy integration
|
||||||
|
- Diversity and inclusion statements
|
||||||
|
- A/B testing variations
|
||||||
|
|
||||||
|
### Sales & Networking Tools
|
||||||
|
|
||||||
|
#### LinkedIn Sales Navigator Content Generator
|
||||||
|
- **Status**: Coming Soon
|
||||||
|
- **Description**: Create personalized outreach content for sales professionals.
|
||||||
|
- **Features**:
|
||||||
|
- Prospect research integration
|
||||||
|
- Industry-specific messaging
|
||||||
|
- Personalization tokens
|
||||||
|
- Connection request templates
|
||||||
|
- Follow-up message sequences
|
||||||
|
- Value proposition highlighting
|
||||||
|
- Objection handling responses
|
||||||
|
- Meeting request templates
|
||||||
|
- Industry pain point addressing
|
||||||
|
- ROI demonstration content
|
||||||
|
|
||||||
|
#### LinkedIn InMail Generator
|
||||||
|
- **Status**: Coming Soon
|
||||||
|
- **Description**: Create personalized and effective InMail messages.
|
||||||
|
- **Features**:
|
||||||
|
- Prospect research integration
|
||||||
|
- Personalization token usage
|
||||||
|
- Value proposition highlighting
|
||||||
|
- Call-to-action optimization
|
||||||
|
- Follow-up sequence generation
|
||||||
|
- Objection handling preparation
|
||||||
|
- Industry-specific messaging
|
||||||
|
- A/B testing variations
|
||||||
|
- Compliance checking
|
||||||
|
- Engagement tracking suggestions
|
||||||
|
|
||||||
|
### Learning & Education Tools
|
||||||
|
|
||||||
|
#### LinkedIn Learning Course Description Generator
|
||||||
|
- **Status**: Coming Soon
|
||||||
|
- **Description**: Create compelling descriptions for LinkedIn Learning courses.
|
||||||
|
- **Features**:
|
||||||
|
- Course objective optimization
|
||||||
|
- Learning outcome generation
|
||||||
|
- Prerequisite suggestions
|
||||||
|
- Target audience definition
|
||||||
|
- Skill tag recommendations
|
||||||
|
- Course structure outline
|
||||||
|
- Engagement element suggestions
|
||||||
|
- Completion certificate highlighting
|
||||||
|
- Industry relevance emphasis
|
||||||
|
- Career path integration
|
||||||
|
|
||||||
|
#### LinkedIn Event Description Generator
|
||||||
|
- **Status**: Coming Soon
|
||||||
|
- **Description**: Create compelling event descriptions that drive attendance and engagement.
|
||||||
|
- **Features**:
|
||||||
|
- Event objective highlighting
|
||||||
|
- Speaker bio generation
|
||||||
|
- Agenda formatting
|
||||||
|
- Registration incentive suggestions
|
||||||
|
- Networking opportunity emphasis
|
||||||
|
- Industry relevance integration
|
||||||
|
- Visual content recommendations
|
||||||
|
- Engagement element suggestions
|
||||||
|
- Post-event follow-up content
|
||||||
|
- Attendance tracking integration
|
||||||
|
|
||||||
|
### Community & Engagement Tools
|
||||||
|
|
||||||
|
#### LinkedIn Group Post Generator
|
||||||
|
- **Status**: Coming Soon
|
||||||
|
- **Description**: Create content specifically optimized for LinkedIn Groups.
|
||||||
|
- **Features**:
|
||||||
|
- Group-specific content adaptation
|
||||||
|
- Discussion prompt generation
|
||||||
|
- Community guideline compliance
|
||||||
|
- Engagement optimization
|
||||||
|
- Moderation suggestion
|
||||||
|
- Topic relevance checking
|
||||||
|
- Member value highlighting
|
||||||
|
- Cross-promotion opportunities
|
||||||
|
- Group culture adaptation
|
||||||
|
- Content scheduling
|
||||||
|
|
||||||
|
## Current Status
|
||||||
|
|
||||||
|
The LinkedIn AI Writer currently has the following tools fully implemented and active:
|
||||||
|
|
||||||
|
1. LinkedIn Post Generator
|
||||||
|
2. LinkedIn Article Generator
|
||||||
|
3. LinkedIn Carousel Post Generator
|
||||||
|
4. LinkedIn Video Script Generator
|
||||||
|
5. LinkedIn Comment Response Generator
|
||||||
|
6. LinkedIn Profile Optimizer
|
||||||
|
7. LinkedIn Poll Generator
|
||||||
|
8. LinkedIn Company Page Content Generator
|
||||||
|
|
||||||
|
The remaining tools are marked as "Coming Soon" and will be implemented in future iterations.
|
||||||
|
|
||||||
|
## Future Development
|
||||||
|
|
||||||
|
### LinkedIn API Integration
|
||||||
|
|
||||||
|
To provide more personalized and effective content, future development will include integration with the LinkedIn API. This will allow:
|
||||||
|
|
||||||
|
- Access to user profile data for personalized content
|
||||||
|
- Direct posting to LinkedIn
|
||||||
|
- Analytics integration for content performance tracking
|
||||||
|
- Engagement metrics for content optimization
|
||||||
|
- Audience insights for targeted content creation
|
||||||
|
|
||||||
|
### Enhanced AI Models
|
||||||
|
|
||||||
|
We plan to enhance the AI models used for content generation to:
|
||||||
|
|
||||||
|
- Better understand LinkedIn's algorithm and best practices
|
||||||
|
- Generate more engaging and platform-specific content
|
||||||
|
- Provide more accurate engagement predictions
|
||||||
|
- Create more personalized content based on user data
|
||||||
|
|
||||||
|
### Additional Features
|
||||||
|
|
||||||
|
Future iterations will include:
|
||||||
|
|
||||||
|
- Content calendar planning and scheduling
|
||||||
|
- Multi-platform content adaptation
|
||||||
|
- Advanced analytics and reporting
|
||||||
|
- Team collaboration features
|
||||||
|
- Content approval workflows
|
||||||
|
- A/B testing capabilities
|
||||||
|
- Custom templates and brand voice settings
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
To use the LinkedIn AI Writer:
|
||||||
|
|
||||||
|
1. Navigate to the LinkedIn AI Writer dashboard
|
||||||
|
2. Select the tool you want to use
|
||||||
|
3. Fill in the required information
|
||||||
|
4. Generate your content
|
||||||
|
5. Review and edit as needed
|
||||||
|
6. Copy the content to your LinkedIn account
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- Python 3.11
|
||||||
|
- Streamlit
|
||||||
|
- OpenAI API key (for GPT models)
|
||||||
|
- Optional: LinkedIn API credentials (for future integration)
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
We welcome contributions to the LinkedIn AI Writer project. Please feel free to submit issues, feature requests, or pull requests.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This project is licensed under the MIT License - see the LICENSE file for details.
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
"""
|
||||||
|
LinkedIn Company Page Content Generator Module
|
||||||
|
|
||||||
|
This module provides tools for generating and optimizing content for LinkedIn company pages.
|
||||||
|
It includes features for company profile optimization, content generation, and engagement tracking.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .linkedin_company_page_generator import LinkedInCompanyPageGenerator
|
||||||
|
from .linkedin_company_page_generator_ui import linkedin_company_page_generator_ui
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'LinkedInCompanyPageGenerator',
|
||||||
|
'linkedin_company_page_generator_ui'
|
||||||
|
]
|
||||||
@@ -0,0 +1,322 @@
|
|||||||
|
"""
|
||||||
|
LinkedIn Company Page Content Generator
|
||||||
|
|
||||||
|
This module provides the core functionality for generating and optimizing LinkedIn company page content.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
from typing import Dict, List, Optional, Union
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
from .....gpt_providers.text_generation.main_text_generation import llm_text_gen
|
||||||
|
from .....ai_web_researcher.gpt_online_researcher import do_google_serp_search
|
||||||
|
from .....ai_web_researcher.metaphor_basic_neural_web_search import metaphor_search_articles
|
||||||
|
from .....ai_web_researcher.tavily_ai_search import do_tavily_ai_search
|
||||||
|
from .....gpt_providers.text_to_image_generation.main_generate_image_from_prompt import generate_image
|
||||||
|
|
||||||
|
class LinkedInCompanyPageGenerator:
|
||||||
|
"""Main class for generating LinkedIn company page content."""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
"""Initialize the LinkedIn Company Page Generator."""
|
||||||
|
self.company_info = {}
|
||||||
|
self.brand_voice = {}
|
||||||
|
self.content_history = []
|
||||||
|
|
||||||
|
async def optimize_company_profile(
|
||||||
|
self,
|
||||||
|
company_name: str,
|
||||||
|
industry: str,
|
||||||
|
target_audience: List[str],
|
||||||
|
brand_voice: str,
|
||||||
|
key_products: List[str],
|
||||||
|
company_size: str,
|
||||||
|
company_description: str
|
||||||
|
) -> Dict[str, str]:
|
||||||
|
"""
|
||||||
|
Optimize the company profile content for LinkedIn.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
company_name: Name of the company
|
||||||
|
industry: Industry sector
|
||||||
|
target_audience: List of target audience segments
|
||||||
|
brand_voice: Desired brand voice/tone
|
||||||
|
key_products: List of key products/services
|
||||||
|
company_size: Size of the company
|
||||||
|
company_description: Current company description
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict containing optimized profile sections
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Store company info for future content generation
|
||||||
|
self.company_info = {
|
||||||
|
"name": company_name,
|
||||||
|
"industry": industry,
|
||||||
|
"target_audience": target_audience,
|
||||||
|
"brand_voice": brand_voice,
|
||||||
|
"key_products": key_products,
|
||||||
|
"size": company_size,
|
||||||
|
"description": company_description
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create the prompt for profile optimization
|
||||||
|
prompt = f"""
|
||||||
|
Optimize the LinkedIn company profile for {company_name}, a {company_size} company in the {industry} industry.
|
||||||
|
|
||||||
|
Current Description:
|
||||||
|
{company_description}
|
||||||
|
|
||||||
|
Key Products/Services:
|
||||||
|
{', '.join(key_products)}
|
||||||
|
|
||||||
|
Target Audience:
|
||||||
|
{', '.join(target_audience)}
|
||||||
|
|
||||||
|
Brand Voice:
|
||||||
|
{brand_voice}
|
||||||
|
|
||||||
|
Generate a comprehensive LinkedIn company profile with the following sections:
|
||||||
|
1. Company Overview
|
||||||
|
2. Mission Statement
|
||||||
|
3. Value Proposition
|
||||||
|
4. Industry Expertise
|
||||||
|
5. Company Culture
|
||||||
|
6. Products/Services Overview
|
||||||
|
|
||||||
|
Ensure the content:
|
||||||
|
- Maintains the specified brand voice
|
||||||
|
- Targets the identified audience segments
|
||||||
|
- Highlights key products/services
|
||||||
|
- Optimizes for LinkedIn's algorithm
|
||||||
|
- Includes relevant industry keywords
|
||||||
|
- Maintains professional tone
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Define the JSON structure for the response
|
||||||
|
json_struct = {
|
||||||
|
"company_overview": "string",
|
||||||
|
"mission_statement": "string",
|
||||||
|
"value_proposition": "string",
|
||||||
|
"industry_expertise": "string",
|
||||||
|
"company_culture": "string",
|
||||||
|
"products_services_overview": "string",
|
||||||
|
"recommended_hashtags": ["string"],
|
||||||
|
"seo_keywords": ["string"]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate the optimized profile content
|
||||||
|
response = await llm_text_gen(
|
||||||
|
prompt=prompt,
|
||||||
|
json_struct=json_struct,
|
||||||
|
temperature=0.7
|
||||||
|
)
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error optimizing company profile: {str(e)}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
async def generate_company_update(
|
||||||
|
self,
|
||||||
|
update_type: str,
|
||||||
|
topic: str,
|
||||||
|
target_audience: Optional[List[str]] = None,
|
||||||
|
include_hashtags: bool = True,
|
||||||
|
include_cta: bool = True
|
||||||
|
) -> Dict[str, str]:
|
||||||
|
"""
|
||||||
|
Generate a company update post for LinkedIn.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
update_type: Type of update (product_launch, milestone, news, etc.)
|
||||||
|
topic: Main topic or focus of the update
|
||||||
|
target_audience: Optional list of target audience segments
|
||||||
|
include_hashtags: Whether to include hashtags
|
||||||
|
include_cta: Whether to include a call-to-action
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict containing the generated update content
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Use company info if target audience not specified
|
||||||
|
if not target_audience:
|
||||||
|
target_audience = self.company_info.get("target_audience", [])
|
||||||
|
|
||||||
|
# Create the prompt for update generation
|
||||||
|
prompt = f"""
|
||||||
|
Generate a LinkedIn company update post for {self.company_info['name']} about {topic}.
|
||||||
|
|
||||||
|
Update Type: {update_type}
|
||||||
|
Target Audience: {', '.join(target_audience)}
|
||||||
|
Brand Voice: {self.company_info['brand_voice']}
|
||||||
|
|
||||||
|
The post should:
|
||||||
|
- Be engaging and professional
|
||||||
|
- Include relevant industry context
|
||||||
|
- Highlight the company's expertise
|
||||||
|
- Drive meaningful engagement
|
||||||
|
- Be optimized for LinkedIn's algorithm
|
||||||
|
"""
|
||||||
|
|
||||||
|
if include_hashtags:
|
||||||
|
prompt += "\n- Include 3-5 relevant hashtags"
|
||||||
|
|
||||||
|
if include_cta:
|
||||||
|
prompt += "\n- Include a clear call-to-action"
|
||||||
|
|
||||||
|
# Define the JSON structure for the response
|
||||||
|
json_struct = {
|
||||||
|
"post_content": "string",
|
||||||
|
"hashtags": ["string"],
|
||||||
|
"call_to_action": "string",
|
||||||
|
"suggested_image_prompt": "string",
|
||||||
|
"engagement_tips": ["string"]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate the update content
|
||||||
|
response = await llm_text_gen(
|
||||||
|
prompt=prompt,
|
||||||
|
json_struct=json_struct,
|
||||||
|
temperature=0.7
|
||||||
|
)
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error generating company update: {str(e)}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
async def generate_employee_spotlight(
|
||||||
|
self,
|
||||||
|
employee_name: str,
|
||||||
|
role: str,
|
||||||
|
achievements: List[str],
|
||||||
|
spotlight_type: str = "general"
|
||||||
|
) -> Dict[str, str]:
|
||||||
|
"""
|
||||||
|
Generate an employee spotlight post for LinkedIn.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
employee_name: Name of the employee
|
||||||
|
role: Employee's role
|
||||||
|
achievements: List of key achievements
|
||||||
|
spotlight_type: Type of spotlight (general, leadership, innovation, etc.)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict containing the generated spotlight content
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Create the prompt for spotlight generation
|
||||||
|
prompt = f"""
|
||||||
|
Generate a LinkedIn employee spotlight post for {employee_name}, {role} at {self.company_info['name']}.
|
||||||
|
|
||||||
|
Spotlight Type: {spotlight_type}
|
||||||
|
Key Achievements:
|
||||||
|
{chr(10).join(f'- {achievement}' for achievement in achievements)}
|
||||||
|
|
||||||
|
Company Context:
|
||||||
|
Industry: {self.company_info['industry']}
|
||||||
|
Brand Voice: {self.company_info['brand_voice']}
|
||||||
|
|
||||||
|
The post should:
|
||||||
|
- Highlight the employee's contributions
|
||||||
|
- Showcase company culture
|
||||||
|
- Be engaging and professional
|
||||||
|
- Include relevant industry context
|
||||||
|
- Drive meaningful engagement
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Define the JSON structure for the response
|
||||||
|
json_struct = {
|
||||||
|
"spotlight_content": "string",
|
||||||
|
"hashtags": ["string"],
|
||||||
|
"call_to_action": "string",
|
||||||
|
"suggested_image_prompt": "string",
|
||||||
|
"engagement_tips": ["string"]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate the spotlight content
|
||||||
|
response = await llm_text_gen(
|
||||||
|
prompt=prompt,
|
||||||
|
json_struct=json_struct,
|
||||||
|
temperature=0.7
|
||||||
|
)
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error generating employee spotlight: {str(e)}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
async def generate_industry_content(
|
||||||
|
self,
|
||||||
|
content_type: str,
|
||||||
|
topic: str,
|
||||||
|
target_audience: Optional[List[str]] = None
|
||||||
|
) -> Dict[str, str]:
|
||||||
|
"""
|
||||||
|
Generate industry-focused content for LinkedIn.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
content_type: Type of content (insight, trend, analysis, etc.)
|
||||||
|
topic: Main topic or focus
|
||||||
|
target_audience: Optional list of target audience segments
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict containing the generated content
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Use company info if target audience not specified
|
||||||
|
if not target_audience:
|
||||||
|
target_audience = self.company_info.get("target_audience", [])
|
||||||
|
|
||||||
|
# Research industry trends and insights
|
||||||
|
research_results = await do_tavily_ai_search(
|
||||||
|
query=f"{topic} in {self.company_info['industry']} industry trends insights",
|
||||||
|
search_depth="advanced"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create the prompt for content generation
|
||||||
|
prompt = f"""
|
||||||
|
Generate LinkedIn industry content for {self.company_info['name']} about {topic}.
|
||||||
|
|
||||||
|
Content Type: {content_type}
|
||||||
|
Target Audience: {', '.join(target_audience)}
|
||||||
|
Industry: {self.company_info['industry']}
|
||||||
|
Brand Voice: {self.company_info['brand_voice']}
|
||||||
|
|
||||||
|
Research Context:
|
||||||
|
{research_results}
|
||||||
|
|
||||||
|
The content should:
|
||||||
|
- Provide valuable industry insights
|
||||||
|
- Position the company as a thought leader
|
||||||
|
- Be data-driven and professional
|
||||||
|
- Drive meaningful engagement
|
||||||
|
- Include relevant examples and context
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Define the JSON structure for the response
|
||||||
|
json_struct = {
|
||||||
|
"content": "string",
|
||||||
|
"hashtags": ["string"],
|
||||||
|
"call_to_action": "string",
|
||||||
|
"suggested_image_prompt": "string",
|
||||||
|
"engagement_tips": ["string"],
|
||||||
|
"key_insights": ["string"]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate the industry content
|
||||||
|
response = await llm_text_gen(
|
||||||
|
prompt=prompt,
|
||||||
|
json_struct=json_struct,
|
||||||
|
temperature=0.7
|
||||||
|
)
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error generating industry content: {str(e)}")
|
||||||
|
raise
|
||||||
@@ -0,0 +1,321 @@
|
|||||||
|
"""
|
||||||
|
LinkedIn Company Page Generator UI
|
||||||
|
|
||||||
|
This module provides the Streamlit UI for the LinkedIn Company Page Generator.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import streamlit as st
|
||||||
|
import json
|
||||||
|
from typing import Dict, List, Optional
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
from .linkedin_company_page_generator import LinkedInCompanyPageGenerator
|
||||||
|
|
||||||
|
async def linkedin_company_page_generator_ui():
|
||||||
|
"""Main UI function for the LinkedIn Company Page Generator."""
|
||||||
|
|
||||||
|
st.title("🏢 LinkedIn Company Page Content Generator")
|
||||||
|
st.markdown("""
|
||||||
|
Create engaging and professional content for your LinkedIn company page.
|
||||||
|
This tool helps you generate optimized company profiles, updates, employee spotlights, and industry content.
|
||||||
|
""")
|
||||||
|
|
||||||
|
# Initialize the generator
|
||||||
|
generator = LinkedInCompanyPageGenerator()
|
||||||
|
|
||||||
|
# Create tabs for different content types
|
||||||
|
tab1, tab2, tab3, tab4 = st.tabs([
|
||||||
|
"Company Profile",
|
||||||
|
"Company Updates",
|
||||||
|
"Employee Spotlights",
|
||||||
|
"Industry Content"
|
||||||
|
])
|
||||||
|
|
||||||
|
# Company Profile Tab
|
||||||
|
with tab1:
|
||||||
|
st.header("Optimize Your Company Profile")
|
||||||
|
st.markdown("Generate an optimized LinkedIn company profile that highlights your brand and drives engagement.")
|
||||||
|
|
||||||
|
# Company Information Form
|
||||||
|
with st.form("company_profile_form"):
|
||||||
|
company_name = st.text_input("Company Name", placeholder="Enter your company name")
|
||||||
|
industry = st.text_input("Industry", placeholder="e.g., Technology, Healthcare, Finance")
|
||||||
|
company_size = st.selectbox(
|
||||||
|
"Company Size",
|
||||||
|
["1-10", "11-50", "51-200", "201-500", "501-1000", "1000+"]
|
||||||
|
)
|
||||||
|
target_audience = st.multiselect(
|
||||||
|
"Target Audience",
|
||||||
|
["Job Seekers", "Customers", "Partners", "Investors", "Industry Professionals", "Media"],
|
||||||
|
default=["Job Seekers", "Customers"]
|
||||||
|
)
|
||||||
|
brand_voice = st.selectbox(
|
||||||
|
"Brand Voice",
|
||||||
|
["Professional", "Innovative", "Friendly", "Authoritative", "Casual", "Technical"]
|
||||||
|
)
|
||||||
|
key_products = st.text_area(
|
||||||
|
"Key Products/Services",
|
||||||
|
placeholder="Enter your key products or services, one per line"
|
||||||
|
).split("\n")
|
||||||
|
company_description = st.text_area(
|
||||||
|
"Current Company Description",
|
||||||
|
placeholder="Enter your current company description"
|
||||||
|
)
|
||||||
|
|
||||||
|
submit_profile = st.form_submit_button("Generate Optimized Profile")
|
||||||
|
|
||||||
|
if submit_profile:
|
||||||
|
if not all([company_name, industry, target_audience, brand_voice, key_products, company_description]):
|
||||||
|
st.error("Please fill in all required fields.")
|
||||||
|
else:
|
||||||
|
with st.spinner("Generating optimized company profile..."):
|
||||||
|
try:
|
||||||
|
profile_content = await generator.optimize_company_profile(
|
||||||
|
company_name=company_name,
|
||||||
|
industry=industry,
|
||||||
|
target_audience=target_audience,
|
||||||
|
brand_voice=brand_voice,
|
||||||
|
key_products=key_products,
|
||||||
|
company_size=company_size,
|
||||||
|
company_description=company_description
|
||||||
|
)
|
||||||
|
|
||||||
|
# Display the results
|
||||||
|
st.success("Profile generated successfully!")
|
||||||
|
|
||||||
|
# Company Overview
|
||||||
|
st.subheader("Company Overview")
|
||||||
|
st.write(profile_content["company_overview"])
|
||||||
|
|
||||||
|
# Mission Statement
|
||||||
|
st.subheader("Mission Statement")
|
||||||
|
st.write(profile_content["mission_statement"])
|
||||||
|
|
||||||
|
# Value Proposition
|
||||||
|
st.subheader("Value Proposition")
|
||||||
|
st.write(profile_content["value_proposition"])
|
||||||
|
|
||||||
|
# Industry Expertise
|
||||||
|
st.subheader("Industry Expertise")
|
||||||
|
st.write(profile_content["industry_expertise"])
|
||||||
|
|
||||||
|
# Company Culture
|
||||||
|
st.subheader("Company Culture")
|
||||||
|
st.write(profile_content["company_culture"])
|
||||||
|
|
||||||
|
# Products/Services Overview
|
||||||
|
st.subheader("Products/Services Overview")
|
||||||
|
st.write(profile_content["products_services_overview"])
|
||||||
|
|
||||||
|
# SEO Keywords
|
||||||
|
st.subheader("Recommended SEO Keywords")
|
||||||
|
st.write(", ".join(profile_content["seo_keywords"]))
|
||||||
|
|
||||||
|
# Hashtags
|
||||||
|
st.subheader("Recommended Hashtags")
|
||||||
|
st.write(" ".join([f"#{tag}" for tag in profile_content["recommended_hashtags"]]))
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
st.error(f"Error generating profile: {str(e)}")
|
||||||
|
|
||||||
|
# Company Updates Tab
|
||||||
|
with tab2:
|
||||||
|
st.header("Generate Company Updates")
|
||||||
|
st.markdown("Create engaging company updates for your LinkedIn page.")
|
||||||
|
|
||||||
|
# Update Generation Form
|
||||||
|
with st.form("company_update_form"):
|
||||||
|
update_type = st.selectbox(
|
||||||
|
"Update Type",
|
||||||
|
["Product Launch", "Company Milestone", "Industry News", "Company News", "Event Announcement"]
|
||||||
|
)
|
||||||
|
topic = st.text_input("Topic", placeholder="Enter the main topic of your update")
|
||||||
|
target_audience = st.multiselect(
|
||||||
|
"Target Audience",
|
||||||
|
["Job Seekers", "Customers", "Partners", "Investors", "Industry Professionals", "Media"],
|
||||||
|
default=["Customers", "Industry Professionals"]
|
||||||
|
)
|
||||||
|
include_hashtags = st.checkbox("Include Hashtags", value=True)
|
||||||
|
include_cta = st.checkbox("Include Call-to-Action", value=True)
|
||||||
|
|
||||||
|
submit_update = st.form_submit_button("Generate Update")
|
||||||
|
|
||||||
|
if submit_update:
|
||||||
|
if not topic:
|
||||||
|
st.error("Please enter a topic for your update.")
|
||||||
|
else:
|
||||||
|
with st.spinner("Generating company update..."):
|
||||||
|
try:
|
||||||
|
update_content = await generator.generate_company_update(
|
||||||
|
update_type=update_type,
|
||||||
|
topic=topic,
|
||||||
|
target_audience=target_audience,
|
||||||
|
include_hashtags=include_hashtags,
|
||||||
|
include_cta=include_cta
|
||||||
|
)
|
||||||
|
|
||||||
|
# Display the results
|
||||||
|
st.success("Update generated successfully!")
|
||||||
|
|
||||||
|
# Post Content
|
||||||
|
st.subheader("Generated Post")
|
||||||
|
st.write(update_content["post_content"])
|
||||||
|
|
||||||
|
# Hashtags
|
||||||
|
if include_hashtags:
|
||||||
|
st.subheader("Recommended Hashtags")
|
||||||
|
st.write(" ".join([f"#{tag}" for tag in update_content["hashtags"]]))
|
||||||
|
|
||||||
|
# Call-to-Action
|
||||||
|
if include_cta:
|
||||||
|
st.subheader("Call-to-Action")
|
||||||
|
st.write(update_content["call_to_action"])
|
||||||
|
|
||||||
|
# Engagement Tips
|
||||||
|
st.subheader("Engagement Tips")
|
||||||
|
for tip in update_content["engagement_tips"]:
|
||||||
|
st.write(f"• {tip}")
|
||||||
|
|
||||||
|
# Image Prompt
|
||||||
|
st.subheader("Suggested Image Prompt")
|
||||||
|
st.write(update_content["suggested_image_prompt"])
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
st.error(f"Error generating update: {str(e)}")
|
||||||
|
|
||||||
|
# Employee Spotlights Tab
|
||||||
|
with tab3:
|
||||||
|
st.header("Generate Employee Spotlights")
|
||||||
|
st.markdown("Create engaging employee spotlight posts to showcase your team.")
|
||||||
|
|
||||||
|
# Spotlight Generation Form
|
||||||
|
with st.form("employee_spotlight_form"):
|
||||||
|
employee_name = st.text_input("Employee Name", placeholder="Enter employee's name")
|
||||||
|
role = st.text_input("Role", placeholder="Enter employee's role")
|
||||||
|
achievements = st.text_area(
|
||||||
|
"Key Achievements",
|
||||||
|
placeholder="Enter key achievements, one per line"
|
||||||
|
).split("\n")
|
||||||
|
spotlight_type = st.selectbox(
|
||||||
|
"Spotlight Type",
|
||||||
|
["General", "Leadership", "Innovation", "Team Player", "Career Growth"]
|
||||||
|
)
|
||||||
|
|
||||||
|
submit_spotlight = st.form_submit_button("Generate Spotlight")
|
||||||
|
|
||||||
|
if submit_spotlight:
|
||||||
|
if not all([employee_name, role, achievements]):
|
||||||
|
st.error("Please fill in all required fields.")
|
||||||
|
else:
|
||||||
|
with st.spinner("Generating employee spotlight..."):
|
||||||
|
try:
|
||||||
|
spotlight_content = await generator.generate_employee_spotlight(
|
||||||
|
employee_name=employee_name,
|
||||||
|
role=role,
|
||||||
|
achievements=achievements,
|
||||||
|
spotlight_type=spotlight_type
|
||||||
|
)
|
||||||
|
|
||||||
|
# Display the results
|
||||||
|
st.success("Spotlight generated successfully!")
|
||||||
|
|
||||||
|
# Spotlight Content
|
||||||
|
st.subheader("Generated Spotlight")
|
||||||
|
st.write(spotlight_content["spotlight_content"])
|
||||||
|
|
||||||
|
# Hashtags
|
||||||
|
st.subheader("Recommended Hashtags")
|
||||||
|
st.write(" ".join([f"#{tag}" for tag in spotlight_content["hashtags"]]))
|
||||||
|
|
||||||
|
# Call-to-Action
|
||||||
|
st.subheader("Call-to-Action")
|
||||||
|
st.write(spotlight_content["call_to_action"])
|
||||||
|
|
||||||
|
# Engagement Tips
|
||||||
|
st.subheader("Engagement Tips")
|
||||||
|
for tip in spotlight_content["engagement_tips"]:
|
||||||
|
st.write(f"• {tip}")
|
||||||
|
|
||||||
|
# Image Prompt
|
||||||
|
st.subheader("Suggested Image Prompt")
|
||||||
|
st.write(spotlight_content["suggested_image_prompt"])
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
st.error(f"Error generating spotlight: {str(e)}")
|
||||||
|
|
||||||
|
# Industry Content Tab
|
||||||
|
with tab4:
|
||||||
|
st.header("Generate Industry Content")
|
||||||
|
st.markdown("Create thought leadership content to position your company as an industry expert.")
|
||||||
|
|
||||||
|
# Industry Content Generation Form
|
||||||
|
with st.form("industry_content_form"):
|
||||||
|
content_type = st.selectbox(
|
||||||
|
"Content Type",
|
||||||
|
["Industry Insight", "Trend Analysis", "Best Practices", "Case Study", "Market Update"]
|
||||||
|
)
|
||||||
|
topic = st.text_input("Topic", placeholder="Enter the main topic of your content")
|
||||||
|
target_audience = st.multiselect(
|
||||||
|
"Target Audience",
|
||||||
|
["Job Seekers", "Customers", "Partners", "Investors", "Industry Professionals", "Media"],
|
||||||
|
default=["Industry Professionals", "Customers"]
|
||||||
|
)
|
||||||
|
|
||||||
|
submit_content = st.form_submit_button("Generate Content")
|
||||||
|
|
||||||
|
if submit_content:
|
||||||
|
if not topic:
|
||||||
|
st.error("Please enter a topic for your content.")
|
||||||
|
else:
|
||||||
|
with st.spinner("Generating industry content..."):
|
||||||
|
try:
|
||||||
|
content = await generator.generate_industry_content(
|
||||||
|
content_type=content_type,
|
||||||
|
topic=topic,
|
||||||
|
target_audience=target_audience
|
||||||
|
)
|
||||||
|
|
||||||
|
# Display the results
|
||||||
|
st.success("Content generated successfully!")
|
||||||
|
|
||||||
|
# Content
|
||||||
|
st.subheader("Generated Content")
|
||||||
|
st.write(content["content"])
|
||||||
|
|
||||||
|
# Key Insights
|
||||||
|
st.subheader("Key Insights")
|
||||||
|
for insight in content["key_insights"]:
|
||||||
|
st.write(f"• {insight}")
|
||||||
|
|
||||||
|
# Hashtags
|
||||||
|
st.subheader("Recommended Hashtags")
|
||||||
|
st.write(" ".join([f"#{tag}" for tag in content["hashtags"]]))
|
||||||
|
|
||||||
|
# Call-to-Action
|
||||||
|
st.subheader("Call-to-Action")
|
||||||
|
st.write(content["call_to_action"])
|
||||||
|
|
||||||
|
# Engagement Tips
|
||||||
|
st.subheader("Engagement Tips")
|
||||||
|
for tip in content["engagement_tips"]:
|
||||||
|
st.write(f"• {tip}")
|
||||||
|
|
||||||
|
# Image Prompt
|
||||||
|
st.subheader("Suggested Image Prompt")
|
||||||
|
st.write(content["suggested_image_prompt"])
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
st.error(f"Error generating content: {str(e)}")
|
||||||
|
|
||||||
|
# Add a footer with tips
|
||||||
|
st.markdown("---")
|
||||||
|
st.markdown("""
|
||||||
|
### Tips for Effective LinkedIn Company Page Content:
|
||||||
|
|
||||||
|
- **Consistency**: Maintain a consistent posting schedule and brand voice
|
||||||
|
- **Engagement**: Encourage comments and discussions on your posts
|
||||||
|
- **Visuals**: Use high-quality images and videos to increase engagement
|
||||||
|
- **Hashtags**: Use relevant industry hashtags to increase visibility
|
||||||
|
- **Analytics**: Monitor your content performance and adjust your strategy
|
||||||
|
- **Employee Advocacy**: Encourage employees to share and engage with company content
|
||||||
|
""")
|
||||||
165
lib/ai_writers/twitter_writers/README.md
Normal file
165
lib/ai_writers/twitter_writers/README.md
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
# Twitter AI Writer Module
|
||||||
|
|
||||||
|
A comprehensive suite of AI-powered tools for Twitter/X content marketing and management.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
### 1. Tweet Generation & Optimization
|
||||||
|
- **Smart Tweet Generator**
|
||||||
|
- Multiple tweet variations based on input parameters
|
||||||
|
- Character count optimization
|
||||||
|
- Hashtag suggestions and placement
|
||||||
|
- Emoji usage recommendations
|
||||||
|
- Thread creation capabilities
|
||||||
|
|
||||||
|
- **Tweet Performance Predictor**
|
||||||
|
- Engagement rate estimation
|
||||||
|
- Best time to post suggestions
|
||||||
|
- Audience reach predictions
|
||||||
|
- Viral potential scoring
|
||||||
|
|
||||||
|
### 2. Content Strategy Tools
|
||||||
|
- **Content Calendar Generator**
|
||||||
|
- Weekly/monthly content planning
|
||||||
|
- Theme-based content scheduling
|
||||||
|
- Event and holiday integration
|
||||||
|
- Content mix recommendations
|
||||||
|
|
||||||
|
- **Hashtag Strategy Manager**
|
||||||
|
- Trending hashtag research
|
||||||
|
- Custom hashtag creation
|
||||||
|
- Hashtag performance tracking
|
||||||
|
- Competitor hashtag analysis
|
||||||
|
|
||||||
|
### 3. Visual Content Creation
|
||||||
|
- **Image Generator**
|
||||||
|
- Tweet card creation
|
||||||
|
- Infographic templates
|
||||||
|
- Quote card designs
|
||||||
|
- Brand-consistent visuals
|
||||||
|
|
||||||
|
- **Video Content Assistant**
|
||||||
|
- Video script generation
|
||||||
|
- Storyboard creation
|
||||||
|
- Caption optimization
|
||||||
|
- Thumbnail design suggestions
|
||||||
|
|
||||||
|
### 4. Engagement & Community Management
|
||||||
|
- **Reply Generator**
|
||||||
|
- Context-aware responses
|
||||||
|
- Tone matching
|
||||||
|
- Crisis management templates
|
||||||
|
- Customer service responses
|
||||||
|
|
||||||
|
- **Community Engagement Tools**
|
||||||
|
- Poll creation
|
||||||
|
- Q&A session planning
|
||||||
|
- Community highlight suggestions
|
||||||
|
- User-generated content prompts
|
||||||
|
|
||||||
|
### 5. Analytics & Optimization
|
||||||
|
- **Performance Analytics**
|
||||||
|
- Tweet performance tracking
|
||||||
|
- Engagement metrics analysis
|
||||||
|
- Audience growth monitoring
|
||||||
|
- Content effectiveness scoring
|
||||||
|
|
||||||
|
- **A/B Testing Assistant**
|
||||||
|
- Tweet variation testing
|
||||||
|
- Headline optimization
|
||||||
|
- CTA effectiveness analysis
|
||||||
|
- Best performing content identification
|
||||||
|
|
||||||
|
### 6. Research & Intelligence
|
||||||
|
- **Market Research Tools**
|
||||||
|
- Competitor analysis
|
||||||
|
- Industry trend tracking
|
||||||
|
- Audience sentiment analysis
|
||||||
|
- Content gap identification
|
||||||
|
|
||||||
|
- **Content Inspiration**
|
||||||
|
- Trending topic suggestions
|
||||||
|
- Content idea generation
|
||||||
|
- Viral content analysis
|
||||||
|
- Industry-specific insights
|
||||||
|
|
||||||
|
## Best Practices Integration
|
||||||
|
|
||||||
|
### Tweet Optimization
|
||||||
|
- Optimal character count (240-280)
|
||||||
|
- Strategic hashtag placement
|
||||||
|
- Effective use of mentions and links
|
||||||
|
- Engaging call-to-actions
|
||||||
|
- Visual content optimization
|
||||||
|
|
||||||
|
### Content Strategy
|
||||||
|
- Consistent brand voice
|
||||||
|
- Regular posting schedule
|
||||||
|
- Content variety maintenance
|
||||||
|
- Engagement-driven approach
|
||||||
|
- Community building focus
|
||||||
|
|
||||||
|
### Visual Content
|
||||||
|
- Image size optimization
|
||||||
|
- Brand color consistency
|
||||||
|
- Text overlay best practices
|
||||||
|
- Mobile-friendly design
|
||||||
|
- Visual hierarchy principles
|
||||||
|
|
||||||
|
### Engagement
|
||||||
|
- Response time optimization
|
||||||
|
- Community management guidelines
|
||||||
|
- Crisis communication protocols
|
||||||
|
- User interaction best practices
|
||||||
|
- Content moderation assistance
|
||||||
|
|
||||||
|
## Technical Integration
|
||||||
|
|
||||||
|
### API Integration
|
||||||
|
- Twitter API v2 support
|
||||||
|
- Rate limit management
|
||||||
|
- Error handling
|
||||||
|
- Data synchronization
|
||||||
|
|
||||||
|
### Performance Optimization
|
||||||
|
- Caching mechanisms
|
||||||
|
- Batch processing
|
||||||
|
- Resource optimization
|
||||||
|
- Response time improvement
|
||||||
|
|
||||||
|
## Security & Compliance
|
||||||
|
|
||||||
|
### Data Protection
|
||||||
|
- User data encryption
|
||||||
|
- Secure API key management
|
||||||
|
- Privacy compliance
|
||||||
|
- Data retention policies
|
||||||
|
|
||||||
|
### Content Guidelines
|
||||||
|
- Platform policy compliance
|
||||||
|
- Copyright protection
|
||||||
|
- Brand safety measures
|
||||||
|
- Content moderation rules
|
||||||
|
|
||||||
|
## Coming Soon
|
||||||
|
- Advanced thread generator
|
||||||
|
- AI-powered image editor
|
||||||
|
- Real-time trend analyzer
|
||||||
|
- Automated content scheduler
|
||||||
|
- Advanced analytics dashboard
|
||||||
|
- Multi-account management
|
||||||
|
- Custom AI model training
|
||||||
|
- Integration with other social platforms
|
||||||
|
|
||||||
|
## Usage Guidelines
|
||||||
|
1. Ensure API keys are properly configured
|
||||||
|
2. Follow Twitter's terms of service
|
||||||
|
3. Maintain brand voice consistency
|
||||||
|
4. Regular content calendar updates
|
||||||
|
5. Monitor performance metrics
|
||||||
|
6. Engage with community regularly
|
||||||
|
7. Update content strategy based on analytics
|
||||||
|
8. Follow security best practices
|
||||||
|
|
||||||
|
## Support
|
||||||
|
For technical support or feature requests, please contact the development team or raise an issue in the repository. https://github.com/AJaySi/AI-Writer/issues
|
||||||
9
lib/ai_writers/twitter_writers/__init__.py
Normal file
9
lib/ai_writers/twitter_writers/__init__.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
"""
|
||||||
|
Twitter AI Writer Module
|
||||||
|
|
||||||
|
A comprehensive suite of AI-powered tools for Twitter/X content marketing and management.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .twitter_dashboard import run_dashboard
|
||||||
|
|
||||||
|
__all__ = ['run_dashboard']
|
||||||
163
lib/ai_writers/twitter_writers/tweet_generator/README.md
Normal file
163
lib/ai_writers/twitter_writers/tweet_generator/README.md
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
Here’s an improved and enhanced version of your README. I've structured it for clarity, conciseness, and professionalism, while also making it more engaging and user-friendly.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🐦 Smart Tweet Generator
|
||||||
|
|
||||||
|
**Create tweets that stand out!** The Smart Tweet Generator is a cutting-edge AI-powered tool designed to craft optimized, engaging tweets that maximize your audience reach and engagement.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✨ Key Features
|
||||||
|
|
||||||
|
### 1. **Multi-Variation Tweet Generation**
|
||||||
|
- Generate 1–5 tweet variations from a single prompt.
|
||||||
|
- Each variation tailored to different engagement styles.
|
||||||
|
- Consistent tone and messaging across all versions.
|
||||||
|
|
||||||
|
### 2. **Real-Time Character Optimization**
|
||||||
|
- Live character count tracking, including emoji support.
|
||||||
|
- Visual indicators to maintain the ideal tweet length.
|
||||||
|
- Alerts when nearing Twitter's 280-character limit.
|
||||||
|
|
||||||
|
### 3. **Intelligent Hashtag Management**
|
||||||
|
- Auto-extract hashtags from generated tweets.
|
||||||
|
- Topic-based, AI-suggested hashtags to enhance discoverability.
|
||||||
|
- Recommendations for optimal hashtag count and placement.
|
||||||
|
|
||||||
|
### 4. **Emoji Suggestions That Fit**
|
||||||
|
- Context-sensitive and tone-appropriate emoji suggestions.
|
||||||
|
- Categories include:
|
||||||
|
- **Humorous**: 😄 😂 😉
|
||||||
|
- **Informative**: 📊 🔍 💡
|
||||||
|
- **Inspirational**: ✨ 🌟 🔥
|
||||||
|
- **Serious**: 🤔 📢 🔔
|
||||||
|
- **Casual**: 👋 👍 🤗
|
||||||
|
|
||||||
|
### 5. **Performance Prediction**
|
||||||
|
- Engagement score (0-100%) based on AI analysis.
|
||||||
|
- Metrics analyzed include:
|
||||||
|
- Character count optimization.
|
||||||
|
- Hashtag effectiveness.
|
||||||
|
- Emoji usage.
|
||||||
|
- Audience relevance.
|
||||||
|
- Categories:
|
||||||
|
- **Excellent** (80–100%)
|
||||||
|
- **Good** (60–79%)
|
||||||
|
- **Fair** (40–59%)
|
||||||
|
- **Needs Improvement** (0–39%)
|
||||||
|
|
||||||
|
### 6. **Actionable Improvement Suggestions**
|
||||||
|
- Real-time feedback on tweet quality.
|
||||||
|
- Tailored recommendations to boost performance.
|
||||||
|
- Built-in best practices guidance for effective tweeting.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 How to Use
|
||||||
|
|
||||||
|
### Step 1: **Enter Basic Information**
|
||||||
|
- Add your tweet topic or hook.
|
||||||
|
- Define the target audience.
|
||||||
|
- Choose the desired tone and tweet length.
|
||||||
|
- Optionally, include a call-to-action (CTA).
|
||||||
|
|
||||||
|
### Step 2: **Customize Advanced Options**
|
||||||
|
- Select the number of tweet variations (1–5).
|
||||||
|
- Input keywords or hashtags.
|
||||||
|
- Choose emoji preferences.
|
||||||
|
- Add @mentions or placeholders for links.
|
||||||
|
|
||||||
|
### Step 3: **Generate and Refine**
|
||||||
|
- Click **Generate Tweets** to create variations.
|
||||||
|
- Review performance metrics and apply improvement suggestions.
|
||||||
|
- Copy, save, or export your favorite version.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Performance Metrics
|
||||||
|
|
||||||
|
**Your tweets are analyzed based on:**
|
||||||
|
|
||||||
|
1. **Character Count**
|
||||||
|
- Optimal: 100–200 characters.
|
||||||
|
- Short: <100 characters.
|
||||||
|
- Long: >200 characters.
|
||||||
|
|
||||||
|
2. **Hashtag Usage**
|
||||||
|
- Optimal: 1–3 hashtags.
|
||||||
|
- Too few: 0 hashtags.
|
||||||
|
- Too many: >3 hashtags.
|
||||||
|
|
||||||
|
3. **Engagement Triggers**
|
||||||
|
- Questions, CTAs, or interactive elements.
|
||||||
|
|
||||||
|
4. **Emoji Optimization**
|
||||||
|
- Ideal: 1–3 emojis.
|
||||||
|
- Too few: 0 emojis.
|
||||||
|
- Too many: >3 emojis.
|
||||||
|
|
||||||
|
5. **Audience Relevance**
|
||||||
|
- Alignment with keywords, tone, and context.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💡 Best Practices
|
||||||
|
|
||||||
|
1. **Craft Attention-Grabbing Hooks**
|
||||||
|
- Start with bold statements or thought-provoking questions.
|
||||||
|
- Use stats or facts to capture attention.
|
||||||
|
|
||||||
|
2. **Align Tone with Audience**
|
||||||
|
- Maintain consistency with your brand voice.
|
||||||
|
- Adapt tone to audience preferences (e.g., formal, casual).
|
||||||
|
|
||||||
|
3. **Strategic Hashtag Usage**
|
||||||
|
- Use trending and relevant hashtags.
|
||||||
|
- Limit to 1–3 for optimal engagement.
|
||||||
|
|
||||||
|
4. **Effective Emoji Usage**
|
||||||
|
- Enhance meaning and context with emojis.
|
||||||
|
- Match the tone and avoid overuse.
|
||||||
|
|
||||||
|
5. **Clear Calls-to-Action**
|
||||||
|
- Encourage action with clarity and urgency.
|
||||||
|
- Use action verbs like "Discover," "Join," or "Explore."
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 Export Options
|
||||||
|
|
||||||
|
- Copy individual tweets.
|
||||||
|
- Export all variations as a JSON file.
|
||||||
|
- Save performance metrics and recommendations.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠️ Technical Details
|
||||||
|
|
||||||
|
- **Built with:** Streamlit for an intuitive user interface.
|
||||||
|
- **AI-powered:** Advanced natural language models for tweet generation.
|
||||||
|
- **Real-time:** Instant feedback and suggestions.
|
||||||
|
- **Cross-platform compatibility:** Works seamlessly across devices.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Notes
|
||||||
|
|
||||||
|
- Tweets are optimized for Twitter’s 280-character limit.
|
||||||
|
- Performance predictions are derived from AI insights and engagement patterns.
|
||||||
|
- Suggestions adapt to your audience, ensuring relevancy.
|
||||||
|
- Regular updates keep the tool current with Twitter trends.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🤝 Support
|
||||||
|
|
||||||
|
Have questions or feature requests? Reach out to our support team or submit an issue on our GitHub repository.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Last updated: Yesterday*
|
||||||
|
|
||||||
|
---
|
||||||
@@ -0,0 +1,342 @@
|
|||||||
|
import streamlit as st
|
||||||
|
import re
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
from typing import Dict, List, Tuple, Optional
|
||||||
|
import random
|
||||||
|
import emoji
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from ....gpt_providers.text_generation.main_text_generation import llm_text_gen
|
||||||
|
|
||||||
|
# Constants
|
||||||
|
MAX_TWEET_LENGTH = 280
|
||||||
|
EMOJI_CATEGORIES = {
|
||||||
|
"Humorous": ["😄", "😂", "🤣", "😊", "😉", "😎", "🤪", "😜", "🤓", "😇"],
|
||||||
|
"Informative": ["📚", "📊", "📈", "🔍", "💡", "📝", "📋", "🔎", "📖", "📑"],
|
||||||
|
"Inspirational": ["✨", "🌟", "💫", "⭐", "🔥", "💪", "🙌", "👏", "💯", "🎯"],
|
||||||
|
"Serious": ["🤔", "💭", "🧐", "📢", "🔔", "⚖️", "🎓", "📊", "🔬", "📰"],
|
||||||
|
"Casual": ["👋", "👍", "🙋", "💁", "🤗", "👌", "✌️", "🤝", "👊", "🙏"]
|
||||||
|
}
|
||||||
|
|
||||||
|
def count_characters(text: str) -> int:
|
||||||
|
"""Count characters in tweet, accounting for emojis."""
|
||||||
|
return len(text)
|
||||||
|
|
||||||
|
def extract_hashtags(text: str) -> List[str]:
|
||||||
|
"""Extract hashtags from tweet text."""
|
||||||
|
return re.findall(r'#\w+', text)
|
||||||
|
|
||||||
|
def suggest_hashtags(topic: str, tone: str) -> List[str]:
|
||||||
|
"""Suggest relevant hashtags based on topic and tone."""
|
||||||
|
# Enhanced hashtag suggestions based on topic and tone
|
||||||
|
base_hashtags = {
|
||||||
|
"professional": ["#Business", "#Leadership", "#Innovation"],
|
||||||
|
"casual": ["#Life", "#Fun", "#Trending"],
|
||||||
|
"informative": ["#Learn", "#Tips", "#HowTo"],
|
||||||
|
"humorous": ["#Funny", "#LOL", "#Humor"],
|
||||||
|
"inspirational": ["#Motivation", "#Success", "#Growth"]
|
||||||
|
}
|
||||||
|
|
||||||
|
topic_hashtags = {
|
||||||
|
"tech": ["#Technology", "#TechNews", "#Innovation"],
|
||||||
|
"business": ["#Business", "#Entrepreneurship", "#Startup"],
|
||||||
|
"marketing": ["#Marketing", "#DigitalMarketing", "#SocialMedia"],
|
||||||
|
"education": ["#Education", "#Learning", "#Knowledge"],
|
||||||
|
"health": ["#Health", "#Wellness", "#Fitness"]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Combine base and topic hashtags
|
||||||
|
suggested = base_hashtags.get(tone.lower(), []) + topic_hashtags.get(topic.lower(), [])
|
||||||
|
return list(set(suggested))[:5] # Return unique hashtags, max 5
|
||||||
|
|
||||||
|
def suggest_emojis(tone: str, count: int = 3) -> List[str]:
|
||||||
|
"""Suggest emojis based on tone."""
|
||||||
|
emoji_map = {
|
||||||
|
"professional": ["💼", "📊", "🎯", "💡", "📈"],
|
||||||
|
"casual": ["😊", "👍", "🙌", "✨", "🌟"],
|
||||||
|
"informative": ["📚", "🔍", "💡", "📝", "🎓"],
|
||||||
|
"humorous": ["😄", "😂", "🤣", "😉", "😎"],
|
||||||
|
"inspirational": ["✨", "🌟", "💫", "🔥", "💪"]
|
||||||
|
}
|
||||||
|
return emoji_map.get(tone.lower(), ["✨"])[:count]
|
||||||
|
|
||||||
|
def predict_tweet_performance(tweet: str, target_audience: str, tone: str) -> Dict:
|
||||||
|
"""Predict tweet performance with enhanced metrics."""
|
||||||
|
char_count = count_characters(tweet)
|
||||||
|
hashtags = extract_hashtags(tweet)
|
||||||
|
|
||||||
|
# Enhanced performance metrics
|
||||||
|
metrics = {
|
||||||
|
"character_count": {
|
||||||
|
"score": min(100, (char_count / 280) * 100),
|
||||||
|
"status": "optimal" if 100 <= char_count <= 200 else "suboptimal",
|
||||||
|
"suggestion": "Consider adjusting length for optimal engagement" if char_count < 100 or char_count > 200 else "Length is optimal"
|
||||||
|
},
|
||||||
|
"hashtag_usage": {
|
||||||
|
"score": min(100, (len(hashtags) / 3) * 100),
|
||||||
|
"status": "optimal" if 1 <= len(hashtags) <= 3 else "suboptimal",
|
||||||
|
"suggestion": "Add more hashtags" if len(hashtags) < 1 else "Reduce hashtag count" if len(hashtags) > 3 else "Hashtag count is optimal"
|
||||||
|
},
|
||||||
|
"engagement_potential": {
|
||||||
|
"score": 0,
|
||||||
|
"status": "needs_improvement",
|
||||||
|
"suggestion": ""
|
||||||
|
},
|
||||||
|
"audience_alignment": {
|
||||||
|
"score": 0,
|
||||||
|
"status": "needs_improvement",
|
||||||
|
"suggestion": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Calculate engagement potential
|
||||||
|
engagement_triggers = ["?", "!", "RT", "like", "follow", "check", "learn", "discover"]
|
||||||
|
trigger_count = sum(1 for trigger in engagement_triggers if trigger.lower() in tweet.lower())
|
||||||
|
metrics["engagement_potential"]["score"] = min(100, (trigger_count / 3) * 100)
|
||||||
|
metrics["engagement_potential"]["status"] = "optimal" if trigger_count >= 1 else "needs_improvement"
|
||||||
|
metrics["engagement_potential"]["suggestion"] = "Add engagement triggers" if trigger_count < 1 else "Good engagement potential"
|
||||||
|
|
||||||
|
# Calculate audience alignment
|
||||||
|
audience_keywords = {
|
||||||
|
"professionals": ["business", "industry", "professional", "career"],
|
||||||
|
"students": ["learn", "study", "education", "student"],
|
||||||
|
"general": ["everyone", "people", "community", "world"]
|
||||||
|
}
|
||||||
|
keyword_count = sum(1 for keyword in audience_keywords.get(target_audience.lower(), [])
|
||||||
|
if keyword.lower() in tweet.lower())
|
||||||
|
metrics["audience_alignment"]["score"] = min(100, (keyword_count / 2) * 100)
|
||||||
|
metrics["audience_alignment"]["status"] = "optimal" if keyword_count >= 1 else "needs_improvement"
|
||||||
|
metrics["audience_alignment"]["suggestion"] = "Add audience-specific keywords" if keyword_count < 1 else "Good audience alignment"
|
||||||
|
|
||||||
|
# Calculate overall score
|
||||||
|
overall_score = sum(metric["score"] for metric in metrics.values()) / len(metrics)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"metrics": metrics,
|
||||||
|
"overall_score": overall_score,
|
||||||
|
"status": "excellent" if overall_score >= 80 else "good" if overall_score >= 60 else "fair" if overall_score >= 40 else "needs_improvement"
|
||||||
|
}
|
||||||
|
|
||||||
|
def generate_tweet_variations(
|
||||||
|
hook: str,
|
||||||
|
target_audience: str,
|
||||||
|
tone: str,
|
||||||
|
call_to_action: str = "",
|
||||||
|
keywords: str = "",
|
||||||
|
length: str = "medium",
|
||||||
|
num_variations: int = 3
|
||||||
|
) -> List[Dict]:
|
||||||
|
"""Generate multiple tweet variations with enhanced AI suggestions."""
|
||||||
|
# Enhanced prompt template for better AI suggestions
|
||||||
|
prompt_template = f"""
|
||||||
|
Create {num_variations} engaging tweet variations with the following parameters:
|
||||||
|
- Hook/Topic: {hook}
|
||||||
|
- Target Audience: {target_audience}
|
||||||
|
- Tone: {tone}
|
||||||
|
- Call to Action: {call_to_action}
|
||||||
|
- Keywords: {keywords}
|
||||||
|
- Length: {length}
|
||||||
|
|
||||||
|
Each tweet should:
|
||||||
|
1. Start with an attention-grabbing hook
|
||||||
|
2. Include relevant hashtags
|
||||||
|
3. Use appropriate emojis
|
||||||
|
4. End with a clear call-to-action
|
||||||
|
5. Stay within Twitter's character limit
|
||||||
|
6. Match the specified tone and audience
|
||||||
|
|
||||||
|
Format each tweet as a JSON object with:
|
||||||
|
- text: The tweet content
|
||||||
|
- hashtags: List of suggested hashtags
|
||||||
|
- emojis: List of suggested emojis
|
||||||
|
- engagement_score: Predicted engagement score (0-100)
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Simulate AI-generated tweets (replace with actual AI call)
|
||||||
|
sample_tweets = [
|
||||||
|
{
|
||||||
|
"text": f"🚀 {hook} #Innovation #Tech",
|
||||||
|
"hashtags": ["#Innovation", "#Tech"],
|
||||||
|
"emojis": ["🚀"],
|
||||||
|
"engagement_score": 85
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": f"💡 {hook} #Business #Growth",
|
||||||
|
"hashtags": ["#Business", "#Growth"],
|
||||||
|
"emojis": ["💡"],
|
||||||
|
"engagement_score": 75
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": f"✨ {hook} #Success #Leadership",
|
||||||
|
"hashtags": ["#Success", "#Leadership"],
|
||||||
|
"emojis": ["✨"],
|
||||||
|
"engagement_score": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return sample_tweets[:num_variations]
|
||||||
|
|
||||||
|
def suggest_improvements(tweet: str, performance: Dict) -> List[str]:
|
||||||
|
"""Generate actionable improvement suggestions."""
|
||||||
|
suggestions = []
|
||||||
|
metrics = performance["metrics"]
|
||||||
|
|
||||||
|
# Character count suggestions
|
||||||
|
if metrics["character_count"]["status"] == "suboptimal":
|
||||||
|
suggestions.append(f"📝 {metrics['character_count']['suggestion']}")
|
||||||
|
|
||||||
|
# Hashtag suggestions
|
||||||
|
if metrics["hashtag_usage"]["status"] == "suboptimal":
|
||||||
|
suggestions.append(f"#️⃣ {metrics['hashtag_usage']['suggestion']}")
|
||||||
|
|
||||||
|
# Engagement suggestions
|
||||||
|
if metrics["engagement_potential"]["status"] == "needs_improvement":
|
||||||
|
suggestions.append(f"🎯 {metrics['engagement_potential']['suggestion']}")
|
||||||
|
|
||||||
|
# Audience alignment suggestions
|
||||||
|
if metrics["audience_alignment"]["status"] == "needs_improvement":
|
||||||
|
suggestions.append(f"👥 {metrics['audience_alignment']['suggestion']}")
|
||||||
|
|
||||||
|
return suggestions
|
||||||
|
|
||||||
|
def render_tweet_card(tweet: Dict, index: int) -> None:
|
||||||
|
"""Render an enhanced tweet card with interactive elements."""
|
||||||
|
with st.container():
|
||||||
|
st.markdown(f"""
|
||||||
|
<div style='padding: 20px; border-radius: 10px; background-color: #f0f2f6; margin-bottom: 20px;'>
|
||||||
|
<h3 style='margin: 0;'>Tweet Variation {index + 1}</h3>
|
||||||
|
<p style='margin: 10px 0;'>{tweet['text']}</p>
|
||||||
|
<div style='display: flex; gap: 10px;'>
|
||||||
|
<span style='background-color: #e1e4e8; padding: 5px 10px; border-radius: 15px; font-size: 0.8em;'>
|
||||||
|
Score: {tweet['engagement_score']}%
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
""", unsafe_allow_html=True)
|
||||||
|
|
||||||
|
# Interactive elements
|
||||||
|
col1, col2 = st.columns(2)
|
||||||
|
with col1:
|
||||||
|
if st.button(f"Copy Tweet {index + 1}", key=f"copy_{index}"):
|
||||||
|
st.write("Tweet copied to clipboard!")
|
||||||
|
with col2:
|
||||||
|
if st.button(f"Save Tweet {index + 1}", key=f"save_{index}"):
|
||||||
|
st.write("Tweet saved!")
|
||||||
|
|
||||||
|
def smart_tweet_generator():
|
||||||
|
"""Enhanced Smart Tweet Generator with improved UI and AI integration."""
|
||||||
|
st.title("✨ Smart Tweet Generator")
|
||||||
|
st.markdown("Create engaging tweets with AI-powered optimization")
|
||||||
|
|
||||||
|
# Input section with improved UI
|
||||||
|
with st.expander("Tweet Parameters", expanded=True):
|
||||||
|
col1, col2 = st.columns(2)
|
||||||
|
|
||||||
|
with col1:
|
||||||
|
hook = st.text_area("Tweet Hook/Topic",
|
||||||
|
placeholder="Enter your main message or topic...",
|
||||||
|
help="The main message or topic of your tweet")
|
||||||
|
|
||||||
|
target_audience = st.selectbox(
|
||||||
|
"Target Audience",
|
||||||
|
["Professionals", "Students", "General"],
|
||||||
|
help="Select your target audience"
|
||||||
|
)
|
||||||
|
|
||||||
|
tone = st.radio(
|
||||||
|
"Tweet Tone",
|
||||||
|
["Professional", "Casual", "Informative", "Humorous", "Inspirational"],
|
||||||
|
horizontal=True,
|
||||||
|
help="Choose the tone for your tweet"
|
||||||
|
)
|
||||||
|
|
||||||
|
with col2:
|
||||||
|
call_to_action = st.text_input(
|
||||||
|
"Call to Action",
|
||||||
|
placeholder="e.g., Learn more, Follow us...",
|
||||||
|
help="What action do you want your audience to take?"
|
||||||
|
)
|
||||||
|
|
||||||
|
keywords = st.text_input(
|
||||||
|
"Keywords/Hashtags",
|
||||||
|
placeholder="Enter keywords separated by commas",
|
||||||
|
help="Keywords to include in your tweet"
|
||||||
|
)
|
||||||
|
|
||||||
|
length = st.select_slider(
|
||||||
|
"Tweet Length",
|
||||||
|
options=["short", "medium", "long"],
|
||||||
|
value="medium",
|
||||||
|
help="Choose your desired tweet length"
|
||||||
|
)
|
||||||
|
|
||||||
|
num_variations = st.slider(
|
||||||
|
"Number of Variations",
|
||||||
|
min_value=1,
|
||||||
|
max_value=5,
|
||||||
|
value=3,
|
||||||
|
help="How many tweet variations would you like to generate?"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Generate button with loading state
|
||||||
|
if st.button("Generate Tweets", use_container_width=True):
|
||||||
|
with st.spinner("Generating tweet variations..."):
|
||||||
|
tweets = generate_tweet_variations(
|
||||||
|
hook, target_audience, tone,
|
||||||
|
call_to_action, keywords, length,
|
||||||
|
num_variations
|
||||||
|
)
|
||||||
|
|
||||||
|
# Display performance metrics
|
||||||
|
st.markdown("### 📊 Performance Metrics")
|
||||||
|
for tweet in tweets:
|
||||||
|
performance = predict_tweet_performance(tweet["text"], target_audience, tone)
|
||||||
|
|
||||||
|
# Overall score with progress bar
|
||||||
|
st.progress(performance["overall_score"] / 100)
|
||||||
|
st.metric("Overall Score", f"{performance['overall_score']:.1f}%")
|
||||||
|
|
||||||
|
# Detailed metrics in columns
|
||||||
|
cols = st.columns(4)
|
||||||
|
metrics = performance["metrics"]
|
||||||
|
|
||||||
|
with cols[0]:
|
||||||
|
st.metric("Character Count", f"{metrics['character_count']['score']:.1f}%")
|
||||||
|
with cols[1]:
|
||||||
|
st.metric("Hashtag Usage", f"{metrics['hashtag_usage']['score']:.1f}%")
|
||||||
|
with cols[2]:
|
||||||
|
st.metric("Engagement", f"{metrics['engagement_potential']['score']:.1f}%")
|
||||||
|
with cols[3]:
|
||||||
|
st.metric("Audience Fit", f"{metrics['audience_alignment']['score']:.1f}%")
|
||||||
|
|
||||||
|
# Improvement suggestions
|
||||||
|
suggestions = suggest_improvements(tweet["text"], performance)
|
||||||
|
if suggestions:
|
||||||
|
st.markdown("### 💡 Improvement Suggestions")
|
||||||
|
for suggestion in suggestions:
|
||||||
|
st.info(suggestion)
|
||||||
|
|
||||||
|
# Tweet card
|
||||||
|
render_tweet_card(tweet, tweets.index(tweet))
|
||||||
|
|
||||||
|
st.markdown("---")
|
||||||
|
|
||||||
|
# Export options
|
||||||
|
st.markdown("### 📥 Export Options")
|
||||||
|
col1, col2 = st.columns(2)
|
||||||
|
with col1:
|
||||||
|
if st.button("Export as JSON"):
|
||||||
|
st.download_button(
|
||||||
|
"Download JSON",
|
||||||
|
data=json.dumps(tweets, indent=2),
|
||||||
|
file_name=f"tweets_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json",
|
||||||
|
mime="application/json"
|
||||||
|
)
|
||||||
|
with col2:
|
||||||
|
if st.button("Copy All Tweets"):
|
||||||
|
tweet_texts = "\n\n".join(tweet["text"] for tweet in tweets)
|
||||||
|
st.code(tweet_texts)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
smart_tweet_generator()
|
||||||
342
lib/ai_writers/twitter_writers/twitter_dashboard.py
Normal file
342
lib/ai_writers/twitter_writers/twitter_dashboard.py
Normal file
@@ -0,0 +1,342 @@
|
|||||||
|
import streamlit as st
|
||||||
|
import re
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
from typing import Dict, List, Tuple, Optional
|
||||||
|
import random
|
||||||
|
import emoji
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from ....gpt_providers.text_generation.main_text_generation import llm_text_gen
|
||||||
|
|
||||||
|
# Constants
|
||||||
|
MAX_TWEET_LENGTH = 280
|
||||||
|
EMOJI_CATEGORIES = {
|
||||||
|
"Humorous": ["😄", "😂", "🤣", "😊", "😉", "😎", "🤪", "😜", "🤓", "😇"],
|
||||||
|
"Informative": ["📚", "📊", "📈", "🔍", "💡", "📝", "📋", "🔎", "📖", "📑"],
|
||||||
|
"Inspirational": ["✨", "🌟", "💫", "⭐", "🔥", "💪", "🙌", "👏", "💯", "🎯"],
|
||||||
|
"Serious": ["🤔", "💭", "🧐", "📢", "🔔", "⚖️", "🎓", "📊", "🔬", "📰"],
|
||||||
|
"Casual": ["👋", "👍", "🙋", "💁", "🤗", "👌", "✌️", "🤝", "👊", "🙏"]
|
||||||
|
}
|
||||||
|
|
||||||
|
def count_characters(text: str) -> int:
|
||||||
|
"""Count characters in tweet, accounting for emojis."""
|
||||||
|
return len(text)
|
||||||
|
|
||||||
|
def extract_hashtags(text: str) -> List[str]:
|
||||||
|
"""Extract hashtags from tweet text."""
|
||||||
|
return re.findall(r'#\w+', text)
|
||||||
|
|
||||||
|
def suggest_hashtags(topic: str, tone: str) -> List[str]:
|
||||||
|
"""Suggest relevant hashtags based on topic and tone."""
|
||||||
|
# Enhanced hashtag suggestions based on topic and tone
|
||||||
|
base_hashtags = {
|
||||||
|
"professional": ["#Business", "#Leadership", "#Innovation"],
|
||||||
|
"casual": ["#Life", "#Fun", "#Trending"],
|
||||||
|
"informative": ["#Learn", "#Tips", "#HowTo"],
|
||||||
|
"humorous": ["#Funny", "#LOL", "#Humor"],
|
||||||
|
"inspirational": ["#Motivation", "#Success", "#Growth"]
|
||||||
|
}
|
||||||
|
|
||||||
|
topic_hashtags = {
|
||||||
|
"tech": ["#Technology", "#TechNews", "#Innovation"],
|
||||||
|
"business": ["#Business", "#Entrepreneurship", "#Startup"],
|
||||||
|
"marketing": ["#Marketing", "#DigitalMarketing", "#SocialMedia"],
|
||||||
|
"education": ["#Education", "#Learning", "#Knowledge"],
|
||||||
|
"health": ["#Health", "#Wellness", "#Fitness"]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Combine base and topic hashtags
|
||||||
|
suggested = base_hashtags.get(tone.lower(), []) + topic_hashtags.get(topic.lower(), [])
|
||||||
|
return list(set(suggested))[:5] # Return unique hashtags, max 5
|
||||||
|
|
||||||
|
def suggest_emojis(tone: str, count: int = 3) -> List[str]:
|
||||||
|
"""Suggest emojis based on tone."""
|
||||||
|
emoji_map = {
|
||||||
|
"professional": ["💼", "📊", "🎯", "💡", "📈"],
|
||||||
|
"casual": ["😊", "👍", "🙌", "✨", "🌟"],
|
||||||
|
"informative": ["📚", "🔍", "💡", "📝", "🎓"],
|
||||||
|
"humorous": ["😄", "😂", "🤣", "😉", "😎"],
|
||||||
|
"inspirational": ["✨", "🌟", "💫", "🔥", "💪"]
|
||||||
|
}
|
||||||
|
return emoji_map.get(tone.lower(), ["✨"])[:count]
|
||||||
|
|
||||||
|
def predict_tweet_performance(tweet: str, target_audience: str, tone: str) -> Dict:
|
||||||
|
"""Predict tweet performance with enhanced metrics."""
|
||||||
|
char_count = count_characters(tweet)
|
||||||
|
hashtags = extract_hashtags(tweet)
|
||||||
|
|
||||||
|
# Enhanced performance metrics
|
||||||
|
metrics = {
|
||||||
|
"character_count": {
|
||||||
|
"score": min(100, (char_count / 280) * 100),
|
||||||
|
"status": "optimal" if 100 <= char_count <= 200 else "suboptimal",
|
||||||
|
"suggestion": "Consider adjusting length for optimal engagement" if char_count < 100 or char_count > 200 else "Length is optimal"
|
||||||
|
},
|
||||||
|
"hashtag_usage": {
|
||||||
|
"score": min(100, (len(hashtags) / 3) * 100),
|
||||||
|
"status": "optimal" if 1 <= len(hashtags) <= 3 else "suboptimal",
|
||||||
|
"suggestion": "Add more hashtags" if len(hashtags) < 1 else "Reduce hashtag count" if len(hashtags) > 3 else "Hashtag count is optimal"
|
||||||
|
},
|
||||||
|
"engagement_potential": {
|
||||||
|
"score": 0,
|
||||||
|
"status": "needs_improvement",
|
||||||
|
"suggestion": ""
|
||||||
|
},
|
||||||
|
"audience_alignment": {
|
||||||
|
"score": 0,
|
||||||
|
"status": "needs_improvement",
|
||||||
|
"suggestion": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Calculate engagement potential
|
||||||
|
engagement_triggers = ["?", "!", "RT", "like", "follow", "check", "learn", "discover"]
|
||||||
|
trigger_count = sum(1 for trigger in engagement_triggers if trigger.lower() in tweet.lower())
|
||||||
|
metrics["engagement_potential"]["score"] = min(100, (trigger_count / 3) * 100)
|
||||||
|
metrics["engagement_potential"]["status"] = "optimal" if trigger_count >= 1 else "needs_improvement"
|
||||||
|
metrics["engagement_potential"]["suggestion"] = "Add engagement triggers" if trigger_count < 1 else "Good engagement potential"
|
||||||
|
|
||||||
|
# Calculate audience alignment
|
||||||
|
audience_keywords = {
|
||||||
|
"professionals": ["business", "industry", "professional", "career"],
|
||||||
|
"students": ["learn", "study", "education", "student"],
|
||||||
|
"general": ["everyone", "people", "community", "world"]
|
||||||
|
}
|
||||||
|
keyword_count = sum(1 for keyword in audience_keywords.get(target_audience.lower(), [])
|
||||||
|
if keyword.lower() in tweet.lower())
|
||||||
|
metrics["audience_alignment"]["score"] = min(100, (keyword_count / 2) * 100)
|
||||||
|
metrics["audience_alignment"]["status"] = "optimal" if keyword_count >= 1 else "needs_improvement"
|
||||||
|
metrics["audience_alignment"]["suggestion"] = "Add audience-specific keywords" if keyword_count < 1 else "Good audience alignment"
|
||||||
|
|
||||||
|
# Calculate overall score
|
||||||
|
overall_score = sum(metric["score"] for metric in metrics.values()) / len(metrics)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"metrics": metrics,
|
||||||
|
"overall_score": overall_score,
|
||||||
|
"status": "excellent" if overall_score >= 80 else "good" if overall_score >= 60 else "fair" if overall_score >= 40 else "needs_improvement"
|
||||||
|
}
|
||||||
|
|
||||||
|
def generate_tweet_variations(
|
||||||
|
hook: str,
|
||||||
|
target_audience: str,
|
||||||
|
tone: str,
|
||||||
|
call_to_action: str = "",
|
||||||
|
keywords: str = "",
|
||||||
|
length: str = "medium",
|
||||||
|
num_variations: int = 3
|
||||||
|
) -> List[Dict]:
|
||||||
|
"""Generate multiple tweet variations with enhanced AI suggestions."""
|
||||||
|
# Enhanced prompt template for better AI suggestions
|
||||||
|
prompt_template = f"""
|
||||||
|
Create {num_variations} engaging tweet variations with the following parameters:
|
||||||
|
- Hook/Topic: {hook}
|
||||||
|
- Target Audience: {target_audience}
|
||||||
|
- Tone: {tone}
|
||||||
|
- Call to Action: {call_to_action}
|
||||||
|
- Keywords: {keywords}
|
||||||
|
- Length: {length}
|
||||||
|
|
||||||
|
Each tweet should:
|
||||||
|
1. Start with an attention-grabbing hook
|
||||||
|
2. Include relevant hashtags
|
||||||
|
3. Use appropriate emojis
|
||||||
|
4. End with a clear call-to-action
|
||||||
|
5. Stay within Twitter's character limit
|
||||||
|
6. Match the specified tone and audience
|
||||||
|
|
||||||
|
Format each tweet as a JSON object with:
|
||||||
|
- text: The tweet content
|
||||||
|
- hashtags: List of suggested hashtags
|
||||||
|
- emojis: List of suggested emojis
|
||||||
|
- engagement_score: Predicted engagement score (0-100)
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Simulate AI-generated tweets (replace with actual AI call)
|
||||||
|
sample_tweets = [
|
||||||
|
{
|
||||||
|
"text": f"🚀 {hook} #Innovation #Tech",
|
||||||
|
"hashtags": ["#Innovation", "#Tech"],
|
||||||
|
"emojis": ["🚀"],
|
||||||
|
"engagement_score": 85
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": f"💡 {hook} #Business #Growth",
|
||||||
|
"hashtags": ["#Business", "#Growth"],
|
||||||
|
"emojis": ["💡"],
|
||||||
|
"engagement_score": 75
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": f"✨ {hook} #Success #Leadership",
|
||||||
|
"hashtags": ["#Success", "#Leadership"],
|
||||||
|
"emojis": ["✨"],
|
||||||
|
"engagement_score": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return sample_tweets[:num_variations]
|
||||||
|
|
||||||
|
def suggest_improvements(tweet: str, performance: Dict) -> List[str]:
|
||||||
|
"""Generate actionable improvement suggestions."""
|
||||||
|
suggestions = []
|
||||||
|
metrics = performance["metrics"]
|
||||||
|
|
||||||
|
# Character count suggestions
|
||||||
|
if metrics["character_count"]["status"] == "suboptimal":
|
||||||
|
suggestions.append(f"📝 {metrics['character_count']['suggestion']}")
|
||||||
|
|
||||||
|
# Hashtag suggestions
|
||||||
|
if metrics["hashtag_usage"]["status"] == "suboptimal":
|
||||||
|
suggestions.append(f"#️⃣ {metrics['hashtag_usage']['suggestion']}")
|
||||||
|
|
||||||
|
# Engagement suggestions
|
||||||
|
if metrics["engagement_potential"]["status"] == "needs_improvement":
|
||||||
|
suggestions.append(f"🎯 {metrics['engagement_potential']['suggestion']}")
|
||||||
|
|
||||||
|
# Audience alignment suggestions
|
||||||
|
if metrics["audience_alignment"]["status"] == "needs_improvement":
|
||||||
|
suggestions.append(f"👥 {metrics['audience_alignment']['suggestion']}")
|
||||||
|
|
||||||
|
return suggestions
|
||||||
|
|
||||||
|
def render_tweet_card(tweet: Dict, index: int) -> None:
|
||||||
|
"""Render an enhanced tweet card with interactive elements."""
|
||||||
|
with st.container():
|
||||||
|
st.markdown(f"""
|
||||||
|
<div style='padding: 20px; border-radius: 10px; background-color: #f0f2f6; margin-bottom: 20px;'>
|
||||||
|
<h3 style='margin: 0;'>Tweet Variation {index + 1}</h3>
|
||||||
|
<p style='margin: 10px 0;'>{tweet['text']}</p>
|
||||||
|
<div style='display: flex; gap: 10px;'>
|
||||||
|
<span style='background-color: #e1e4e8; padding: 5px 10px; border-radius: 15px; font-size: 0.8em;'>
|
||||||
|
Score: {tweet['engagement_score']}%
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
""", unsafe_allow_html=True)
|
||||||
|
|
||||||
|
# Interactive elements
|
||||||
|
col1, col2 = st.columns(2)
|
||||||
|
with col1:
|
||||||
|
if st.button(f"Copy Tweet {index + 1}", key=f"copy_{index}"):
|
||||||
|
st.write("Tweet copied to clipboard!")
|
||||||
|
with col2:
|
||||||
|
if st.button(f"Save Tweet {index + 1}", key=f"save_{index}"):
|
||||||
|
st.write("Tweet saved!")
|
||||||
|
|
||||||
|
def smart_tweet_generator():
|
||||||
|
"""Enhanced Smart Tweet Generator with improved UI and AI integration."""
|
||||||
|
st.title("✨ Smart Tweet Generator")
|
||||||
|
st.markdown("Create engaging tweets with AI-powered optimization")
|
||||||
|
|
||||||
|
# Input section with improved UI
|
||||||
|
with st.expander("Tweet Parameters", expanded=True):
|
||||||
|
col1, col2 = st.columns(2)
|
||||||
|
|
||||||
|
with col1:
|
||||||
|
hook = st.text_area("Tweet Hook/Topic",
|
||||||
|
placeholder="Enter your main message or topic...",
|
||||||
|
help="The main message or topic of your tweet")
|
||||||
|
|
||||||
|
target_audience = st.selectbox(
|
||||||
|
"Target Audience",
|
||||||
|
["Professionals", "Students", "General"],
|
||||||
|
help="Select your target audience"
|
||||||
|
)
|
||||||
|
|
||||||
|
tone = st.radio(
|
||||||
|
"Tweet Tone",
|
||||||
|
["Professional", "Casual", "Informative", "Humorous", "Inspirational"],
|
||||||
|
horizontal=True,
|
||||||
|
help="Choose the tone for your tweet"
|
||||||
|
)
|
||||||
|
|
||||||
|
with col2:
|
||||||
|
call_to_action = st.text_input(
|
||||||
|
"Call to Action",
|
||||||
|
placeholder="e.g., Learn more, Follow us...",
|
||||||
|
help="What action do you want your audience to take?"
|
||||||
|
)
|
||||||
|
|
||||||
|
keywords = st.text_input(
|
||||||
|
"Keywords/Hashtags",
|
||||||
|
placeholder="Enter keywords separated by commas",
|
||||||
|
help="Keywords to include in your tweet"
|
||||||
|
)
|
||||||
|
|
||||||
|
length = st.select_slider(
|
||||||
|
"Tweet Length",
|
||||||
|
options=["short", "medium", "long"],
|
||||||
|
value="medium",
|
||||||
|
help="Choose your desired tweet length"
|
||||||
|
)
|
||||||
|
|
||||||
|
num_variations = st.slider(
|
||||||
|
"Number of Variations",
|
||||||
|
min_value=1,
|
||||||
|
max_value=5,
|
||||||
|
value=3,
|
||||||
|
help="How many tweet variations would you like to generate?"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Generate button with loading state
|
||||||
|
if st.button("Generate Tweets", use_container_width=True):
|
||||||
|
with st.spinner("Generating tweet variations..."):
|
||||||
|
tweets = generate_tweet_variations(
|
||||||
|
hook, target_audience, tone,
|
||||||
|
call_to_action, keywords, length,
|
||||||
|
num_variations
|
||||||
|
)
|
||||||
|
|
||||||
|
# Display performance metrics
|
||||||
|
st.markdown("### 📊 Performance Metrics")
|
||||||
|
for tweet in tweets:
|
||||||
|
performance = predict_tweet_performance(tweet["text"], target_audience, tone)
|
||||||
|
|
||||||
|
# Overall score with progress bar
|
||||||
|
st.progress(performance["overall_score"] / 100)
|
||||||
|
st.metric("Overall Score", f"{performance['overall_score']:.1f}%")
|
||||||
|
|
||||||
|
# Detailed metrics in columns
|
||||||
|
cols = st.columns(4)
|
||||||
|
metrics = performance["metrics"]
|
||||||
|
|
||||||
|
with cols[0]:
|
||||||
|
st.metric("Character Count", f"{metrics['character_count']['score']:.1f}%")
|
||||||
|
with cols[1]:
|
||||||
|
st.metric("Hashtag Usage", f"{metrics['hashtag_usage']['score']:.1f}%")
|
||||||
|
with cols[2]:
|
||||||
|
st.metric("Engagement", f"{metrics['engagement_potential']['score']:.1f}%")
|
||||||
|
with cols[3]:
|
||||||
|
st.metric("Audience Fit", f"{metrics['audience_alignment']['score']:.1f}%")
|
||||||
|
|
||||||
|
# Improvement suggestions
|
||||||
|
suggestions = suggest_improvements(tweet["text"], performance)
|
||||||
|
if suggestions:
|
||||||
|
st.markdown("### 💡 Improvement Suggestions")
|
||||||
|
for suggestion in suggestions:
|
||||||
|
st.info(suggestion)
|
||||||
|
|
||||||
|
# Tweet card
|
||||||
|
render_tweet_card(tweet, tweets.index(tweet))
|
||||||
|
|
||||||
|
st.markdown("---")
|
||||||
|
|
||||||
|
# Export options
|
||||||
|
st.markdown("### 📥 Export Options")
|
||||||
|
col1, col2 = st.columns(2)
|
||||||
|
with col1:
|
||||||
|
if st.button("Export as JSON"):
|
||||||
|
st.download_button(
|
||||||
|
"Download JSON",
|
||||||
|
data=json.dumps(tweets, indent=2),
|
||||||
|
file_name=f"tweets_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json",
|
||||||
|
mime="application/json"
|
||||||
|
)
|
||||||
|
with col2:
|
||||||
|
if st.button("Copy All Tweets"):
|
||||||
|
tweet_texts = "\n\n".join(tweet["text"] for tweet in tweets)
|
||||||
|
st.code(tweet_texts)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
smart_tweet_generator()
|
||||||
Reference in New Issue
Block a user