LinkedIn / app.py
Toshi94's picture
Update app.py
5b4afea verified
# !pip install --upgrade langchain langchain-core langchain-community langchain-groq gradio python-dotenv
# !pip install langchain-groq
import os
import gradio as gr
import re
from datetime import datetime, timedelta
import json
import random
# from google.colab import userdata
# Import LangChain components
try:
from langchain_groq import ChatGroq
from langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser
print("βœ… All packages imported successfully!")
except ImportError as e:
print(f"❌ Import Error: {e}")
print("\n⚠️ Please run the installation command first:")
print("!pip install --upgrade langchain langchain-core langchain-community langchain-groq gradio python-dotenv")
raise
# =========================
# API Key Configuration
# =========================
#GROQ_API_KEY = "add your api key or load from google secerets"
GROQ_API_KEY = os.getenv('GROQ_API_KEY')
# =========================
# Initialize LLM
# =========================
try:
llm = ChatGroq(
temperature=0.7,
groq_api_key=GROQ_API_KEY,
model_name="llama-3.1-8b-instant"
)
print("βœ… LLM initialized successfully!")
except Exception as e:
print(f"❌ LLM initialization error: {e}")
raise
# =========================
# Enhanced Prompt Templates
# =========================
linkedin_template = """
You are an expert LinkedIn content writer with 10+ years of experience.
Create a highly engaging LinkedIn post that maximizes engagement.
Requirements:
- Start with a powerful hook that stops scrolling
- Use short, punchy paragraphs (2-3 lines max)
- Include storytelling elements or data points
- Add 2-4 relevant emojis naturally throughout
- Use line breaks for visual appeal
- End with an engaging CTA
- Word count: {word_count} words
Topic: {topic}
Tone: {tone}
Target Audience: {audience}
Post Type: {post_type}
{hashtags_instruction}
Write the post now with natural emoji placement.
"""
carousel_template = """
Create a LinkedIn carousel post with {slides} slides.
Each slide should have:
- A catchy title (5-8 words)
- 2-3 bullet points of content
- Relevant emoji
Topic: {topic}
Tone: {tone}
Format each slide as:
SLIDE [number]:
Title: [title]
β€’ [point 1]
β€’ [point 2]
β€’ [point 3]
"""
story_template = """
Create a compelling LinkedIn story post about {topic}.
Use the following structure:
1. Opening hook (2-3 lines)
2. The challenge/situation
3. The turning point
4. The lesson/insight
5. Call to action
Tone: {tone}
Include emojis naturally.
Target length: {word_count} words
"""
thread_template = """
Create a LinkedIn thread with {posts} posts on {topic}.
Each post should:
- Be standalone valuable
- Connect to the overall narrative
- Be 100-150 words
- Include relevant emojis
Tone: {tone}
Format as:
POST 1/[total]:
[content]
POST 2/[total]:
[content]
"""
# =========================
# Post History Storage
# =========================
post_history = []
def save_to_history(post, topic, tone, audience):
"""Save generated post to history"""
entry = {
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"post": post,
"topic": topic,
"tone": tone,
"audience": audience
}
post_history.insert(0, entry)
if len(post_history) > 50:
post_history.pop()
return format_history()
def format_history():
"""Format history for display"""
if not post_history:
return "No posts in history yet. Generate some posts to see them here!"
formatted = []
for idx, entry in enumerate(post_history[:10], 1):
formatted.append(f"""
**Post #{idx}** - {entry['timestamp']}
πŸ“ Topic: {entry['topic']}
🎭 Tone: {entry['tone']} | 🎯 Audience: {entry['audience']}
{entry['post'][:200]}...
---
""")
return "\n".join(formatted)
def get_post_from_history(post_number):
"""Retrieve specific post from history"""
try:
idx = int(post_number) - 1
if 0 <= idx < len(post_history):
return post_history[idx]['post']
return "Invalid post number"
except:
return "Please enter a valid post number"
# =========================
# Schedule Optimizer
# =========================
def get_best_posting_times(industry, audience_location, goal):
"""AI-powered posting time recommendations"""
template = """
You are a LinkedIn marketing expert specializing in optimal posting times.
Analyze and recommend the best 5 posting times for:
Industry: {industry}
Audience Location: {audience_location}
Goal: {goal}
Provide specific day and time recommendations with reasoning.
Format as:
1. [Day] at [Time] - [Reason]
2. [Day] at [Time] - [Reason]
...
Also include:
- Best day of week overall
- Times to avoid
- Frequency recommendation
"""
prompt = PromptTemplate(
input_variables=["industry", "audience_location", "goal"],
template=template
)
chain = prompt | llm | StrOutputParser()
result = chain.invoke({
"industry": industry,
"audience_location": audience_location,
"goal": goal
})
return result
# =========================
# Competitor Analysis
# =========================
def analyze_competitor_post(competitor_post, your_niche):
"""Analyze what makes a post successful"""
template = """
You are a LinkedIn growth expert. Analyze this successful post and extract insights.
Niche/Industry: {niche}
Post to analyze:
{post}
Provide detailed analysis:
1. **Hook Analysis**: Why the opening works
2. **Structure**: How it's organized
3. **Engagement Tactics**: What drives comments/shares
4. **Key Elements**: Specific techniques used
5. **Actionable Tips**: How to replicate success
6. **Improvement Ideas**: What could make it even better
Be specific and tactical.
"""
prompt = PromptTemplate(
input_variables=["niche", "post"],
template=template
)
chain = prompt | llm | StrOutputParser()
result = chain.invoke({
"niche": your_niche,
"post": competitor_post
})
return result
# =========================
# Image Suggestion
# =========================
def suggest_images(post_content, post_type):
"""AI suggests what images/visuals to use"""
template = """
You are a visual content strategist for LinkedIn.
Analyze this post and suggest the best visual content to accompany it.
Post Type: {post_type}
Post Content:
{content}
Suggest:
1. **Primary Image Type**: (e.g., infographic, photo, illustration, chart)
2. **Specific Visual Elements**: What should be shown
3. **Color Scheme**: Recommended colors
4. **Text Overlay**: What text (if any) should be on the image
5. **Style Guidelines**: Professional, casual, modern, etc.
6. **Alternative Options**: 2-3 other visual ideas
7. **Stock Photo Keywords**: Keywords to search for the right image
8. **Design Tools**: Recommended tools (Canva templates, etc.)
Be specific and actionable.
"""
prompt = PromptTemplate(
input_variables=["post_type", "content"],
template=template
)
chain = prompt | llm | StrOutputParser()
result = chain.invoke({
"post_type": post_type,
"content": post_content
})
return result
# =========================
# A/B Testing
# =========================
def generate_ab_versions(topic, tone, audience):
"""Generate two different versions for A/B testing"""
template_a = """
Create Version A - Hook-focused approach:
Topic: {topic}
Tone: {tone}
Audience: {audience}
Start with an extremely powerful, curiosity-driven hook.
Focus on immediate attention-grabbing.
Use pattern interrupts.
150-200 words.
"""
template_b = """
Create Version B - Value-first approach:
Topic: {topic}
Tone: {tone}
Audience: {audience}
Start by immediately delivering value/insight.
Focus on practical takeaways.
Use data or specific examples.
150-200 words.
"""
prompt_a = PromptTemplate(input_variables=["topic", "tone", "audience"], template=template_a)
prompt_b = PromptTemplate(input_variables=["topic", "tone", "audience"], template=template_b)
chain_a = prompt_a | llm | StrOutputParser()
chain_b = prompt_b | llm | StrOutputParser()
version_a = chain_a.invoke({"topic": topic, "tone": tone, "audience": audience})
version_b = chain_b.invoke({"topic": topic, "tone": tone, "audience": audience})
version_a = fix_emoji_encoding(version_a)
version_b = fix_emoji_encoding(version_b)
analytics_a = analyze_post(version_a)
analytics_b = analyze_post(version_b)
comparison = f"""
# πŸ…°οΈ VERSION A - Hook-Focused
**Strategy**: Attention-grabbing hook, curiosity-driven
{version_a}
{format_analytics(analytics_a)}
---
# πŸ…±οΈ VERSION B - Value-First
**Strategy**: Immediate value delivery, practical focus
{version_b}
{format_analytics(analytics_b)}
---
## πŸ“Š A/B Testing Recommendations:
- Test both versions at similar times (Tuesday/Wednesday morning)
- Track: Impressions, Engagement Rate, Comments, Shares
- Run each for 24-48 hours
- The version with higher engagement rate (not just likes) wins
- Consider your audience: C-level prefers Version B, broader audience may prefer Version A
"""
return comparison
# =========================
# Trend Analyzer
# =========================
def analyze_linkedin_trends(industry, timeframe):
"""Get current LinkedIn trending topics"""
template = """
You are a LinkedIn trends analyst with access to current platform data.
Analyze current LinkedIn trends for:
Industry: {industry}
Timeframe: {timeframe}
Provide:
1. **Top 5 Trending Topics**: What's getting traction now
2. **Rising Hashtags**: Trending hashtags to use
3. **Content Formats**: Which formats are performing best (text, carousel, video, etc.)
4. **Engagement Patterns**: What drives engagement now
5. **Topic Ideas**: 5 specific post ideas based on trends
6. **What to Avoid**: Topics that are oversaturated
Be current, specific, and actionable.
"""
prompt = PromptTemplate(
input_variables=["industry", "timeframe"],
template=template
)
chain = prompt | llm | StrOutputParser()
result = chain.invoke({
"industry": industry,
"timeframe": timeframe
})
return result
# =========================
# Personal Branding
# =========================
def create_brand_voice(name, industry, values, personality, expertise):
"""Create a consistent personal brand voice guide"""
template = """
You are a personal branding expert. Create a comprehensive brand voice guide.
Profile:
- Name: {name}
- Industry: {industry}
- Core Values: {values}
- Personality: {personality}
- Key Expertise: {expertise}
Create a detailed brand voice guide including:
1. **Voice Characteristics**: 3-5 key traits
2. **Tone Guidelines**:
- Professional contexts
- Casual contexts
- Thought leadership
3. **Language Do's and Don'ts**:
- Preferred words/phrases
- Words to avoid
4. **Signature Elements**:
- Opening styles
- Closing CTAs
- Emoji usage
5. **Content Pillars**: 5 main topic areas
6. **Example Phrases**: 10 on-brand phrases to use
7. **Differentiation**: What makes this voice unique
Be specific and actionable for consistent LinkedIn presence.
"""
prompt = PromptTemplate(
input_variables=["name", "industry", "values", "personality", "expertise"],
template=template
)
chain = prompt | llm | StrOutputParser()
result = chain.invoke({
"name": name,
"industry": industry,
"values": values,
"personality": personality,
"expertise": expertise
})
return result
def apply_brand_voice(post, brand_guide_summary):
"""Apply brand voice to a post"""
template = """
Rewrite this post to match the brand voice guidelines.
Brand Voice Guidelines:
{brand_guide}
Original Post:
{post}
Rewrite maintaining the core message but adapting tone, language, and style to match the brand voice perfectly.
"""
prompt = PromptTemplate(
input_variables=["brand_guide", "post"],
template=template
)
chain = prompt | llm | StrOutputParser()
result = chain.invoke({
"brand_guide": brand_guide_summary,
"post": post
})
return fix_emoji_encoding(result)
# =========================
# Export Functions - FIXED
# =========================
def export_as_text(content, filename="linkedin_post"):
"""Export post as downloadable text file"""
if not content or not content.strip():
return None
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
full_filename = f"{filename}_{timestamp}.txt"
# Create file in current directory for proper download
try:
with open(full_filename, 'w', encoding='utf-8') as f:
f.write(content)
return full_filename
except Exception as e:
print(f"Export error: {e}")
return None
def create_post_document(posts_list):
"""Create a formatted document with multiple posts"""
if not posts_list:
return ""
doc_content = f"""
LinkedIn Content Package
Generated: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
{'='*80}
"""
for idx, post in enumerate(posts_list, 1):
doc_content += f"""
POST #{idx}
{'-'*80}
{post}
{'='*80}
"""
return doc_content
# =========================
# Helper Functions
# =========================
def suggest_tone(topic):
topic_lower = topic.lower()
if any(word in topic_lower for word in ["success", "growth", "motivation", "inspire"]):
return "Inspirational"
elif any(word in topic_lower for word in ["team", "colleague", "work", "project", "career"]):
return "Professional"
elif any(word in topic_lower for word in ["data", "research", "analysis", "tech"]):
return "Analytical"
else:
return "Friendly"
def suggest_hashtags(topic, count=5):
topic_lower = topic.lower()
hashtag_map = {
"ai": ["#AI", "#MachineLearning", "#DeepLearning", "#Tech", "#Innovation"],
"career": ["#Career", "#Growth", "#ProfessionalDevelopment", "#Leadership", "#Success"],
"team": ["#Teamwork", "#Collaboration", "#Productivity", "#Management", "#Culture"],
"marketing": ["#Marketing", "#DigitalMarketing", "#ContentMarketing", "#Strategy", "#Branding"],
"sales": ["#Sales", "#Business", "#B2B", "#Revenue", "#Growth"],
"leadership": ["#Leadership", "#Management", "#ExecutiveLeadership", "#Vision", "#Strategy"],
"startup": ["#Startup", "#Entrepreneur", "#Innovation", "#Business", "#VC"],
"data": ["#DataScience", "#Analytics", "#BigData", "#DataDriven", "#Insights"]
}
for key, hashtags in hashtag_map.items():
if key in topic_lower:
return " ".join(hashtags[:count])
return "#Inspiration #Learning #Success #Innovation #Growth"
def analyze_post(post):
"""Enhanced analytics"""
words = len(post.split())
paragraphs = post.count("\n\n") + 1
emojis = len(re.findall(r'[^\w\s,.]', post))
hashtags = len(re.findall(r'#\w+', post))
lines = post.count("\n") + 1
# Engagement score calculation
engagement_score = 0
if 150 <= words <= 250:
engagement_score += 30
elif words < 150:
engagement_score += 20
else:
engagement_score += 10
if 3 <= paragraphs <= 5:
engagement_score += 20
if 2 <= emojis <= 5:
engagement_score += 20
if 3 <= hashtags <= 5:
engagement_score += 15
if any(cta in post.lower() for cta in ["comment", "share", "thoughts", "agree", "experience"]):
engagement_score += 15
return {
"words": words,
"paragraphs": paragraphs,
"emojis": emojis,
"hashtags": hashtags,
"lines": lines,
"engagement_score": min(engagement_score, 100)
}
def format_analytics(analytics):
return f"""
πŸ“Š **Post Analytics**
β€’ Words: {analytics['words']}
β€’ Paragraphs: {analytics['paragraphs']}
β€’ Emojis: {analytics['emojis']}
β€’ Hashtags: {analytics['hashtags']}
β€’ Engagement Score: {analytics['engagement_score']}/100
"""
def fix_emoji_encoding(text):
try:
fixed = text.encode('latin-1').decode('utf-8')
return fixed
except (UnicodeDecodeError, UnicodeEncodeError):
return text
def generate_post(topic, tone, audience, post_type, word_count, num_variations, custom_hashtags):
if not topic.strip():
return "Please enter a topic to generate a LinkedIn post."
# Determine hashtags
if custom_hashtags.strip():
hashtags = custom_hashtags
hashtags_instruction = f"Include these hashtags at the end: {hashtags}"
else:
hashtags = suggest_hashtags(topic)
hashtags_instruction = f"Suggest and include 3-5 relevant hashtags at the end"
# Select template based on post type
if post_type == "Standard Post":
template = linkedin_template
prompt = PromptTemplate(
input_variables=["topic", "tone", "audience", "post_type", "word_count", "hashtags_instruction"],
template=template
)
chain = prompt | llm | StrOutputParser()
elif post_type == "Story Post":
template = story_template
prompt = PromptTemplate(
input_variables=["topic", "tone", "word_count"],
template=template
)
chain = prompt | llm | StrOutputParser()
elif post_type == "Carousel (5 slides)":
template = carousel_template
prompt = PromptTemplate(
input_variables=["slides", "topic", "tone"],
template=template
)
chain = prompt | llm | StrOutputParser()
elif post_type == "Thread (3 posts)":
template = thread_template
prompt = PromptTemplate(
input_variables=["posts", "topic", "tone"],
template=template
)
chain = prompt | llm | StrOutputParser()
# Generate variations
variations = []
for i in range(num_variations):
if post_type == "Standard Post":
result = chain.invoke({
"topic": topic,
"tone": tone,
"audience": audience,
"post_type": post_type,
"word_count": word_count,
"hashtags_instruction": hashtags_instruction
})
elif post_type == "Story Post":
result = chain.invoke({
"topic": topic,
"tone": tone,
"word_count": word_count
})
elif post_type == "Carousel (5 slides)":
result = chain.invoke({
"slides": 5,
"topic": topic,
"tone": tone
})
elif post_type == "Thread (3 posts)":
result = chain.invoke({
"posts": 3,
"topic": topic,
"tone": tone
})
result = fix_emoji_encoding(result)
analytics = analyze_post(result)
formatted = f"**Variation {i+1}**\n\n{result}\n\n{format_analytics(analytics)}"
variations.append(formatted)
# Save to history
save_to_history(result, topic, tone, audience)
return "\n\n" + "="*80 + "\n\n".join(variations)
def rewrite_post(original_post, instruction):
"""Rewrite existing post based on user instruction"""
if not original_post.strip():
return "Please paste a post to rewrite."
rewrite_template = """
You are a LinkedIn content expert. Rewrite the following post based on this instruction:
Instruction: {instruction}
Original Post:
{original_post}
Provide the rewritten version maintaining LinkedIn best practices.
"""
prompt = PromptTemplate(
input_variables=["instruction", "original_post"],
template=rewrite_template
)
chain = prompt | llm | StrOutputParser()
result = chain.invoke({
"instruction": instruction,
"original_post": original_post
})
result = fix_emoji_encoding(result)
analytics = analyze_post(result)
return f"{result}\n\n{format_analytics(analytics)}"
def generate_hashtag_suggestions(topic, count):
"""AI-powered hashtag suggestions"""
template = """
Generate {count} highly relevant and trending LinkedIn hashtags for this topic: {topic}
Provide hashtags that:
- Are currently popular on LinkedIn
- Mix broad and niche hashtags
- Include industry-specific tags
- Balance reach and relevance
Return only the hashtags separated by spaces, starting with #
"""
prompt = PromptTemplate(
input_variables=["topic", "count"],
template=template
)
chain = prompt | llm | StrOutputParser()
result = chain.invoke({"topic": topic, "count": count})
return result.strip()
def export_current_post(content):
"""Export the current post as a text file - FIXED"""
if not content or not content.strip():
return None, "❌ Nothing to export! Generate a post first."
# Remove analytics section if present
if "πŸ“Š **Post Analytics**" in content:
content = content.split("πŸ“Š **Post Analytics**")[0].strip()
filepath = export_as_text(content, "linkedin_post")
if filepath:
return filepath, "βœ… Post exported successfully!"
else:
return None, "❌ Export failed. Please try again."
def export_history_package(count):
"""Export multiple posts from history - FIXED"""
try:
count = int(count)
posts_to_export = [entry['post'] for entry in post_history[:count]]
if not posts_to_export:
return None, "No posts to export. Generate some posts first!"
content = create_post_document(posts_to_export)
filepath = export_as_text(content, "linkedin_posts_package")
if filepath:
return filepath, f"βœ… Exported {len(posts_to_export)} posts successfully!"
else:
return None, "❌ Export failed. Please try again."
except Exception as e:
return None, f"❌ Export failed: {str(e)}"
# =========================
# Gradio Interface
# =========================
demo = gr.Blocks()
with demo:
gr.Markdown(
"""
# LinkedIn AI Writer
### The Complete LinkedIn Content Creation Suite with 15+ AI-Powered Features
"""
)
with gr.Tabs():
# Tab 1: Generate New Post
with gr.Tab("✍️ Generate Post"):
with gr.Row():
with gr.Column(scale=1):
topic_input = gr.Textbox(
label="πŸ“ Topic",
placeholder="e.g., How AI is transforming remote work...",
lines=3
)
with gr.Row():
tone_input = gr.Dropdown(
["Professional", "Friendly", "Inspirational", "Analytical", "Humorous"],
label="🎭 Tone",
value="Professional"
)
audience_input = gr.Dropdown(
["General", "C-Level Executives", "Managers", "Individual Contributors", "Students", "Entrepreneurs"],
label="🎯 Target Audience",
value="General"
)
with gr.Row():
post_type_input = gr.Dropdown(
["Standard Post", "Story Post", "Carousel (5 slides)", "Thread (3 posts)"],
label="πŸ“„ Post Type",
value="Standard Post"
)
word_count_input = gr.Slider(
minimum=100,
maximum=300,
step=25,
value=200,
label="πŸ“ Word Count"
)
num_variations_input = gr.Slider(
minimum=1,
maximum=3,
step=1,
value=1,
label="πŸ”’ Number of Variations"
)
custom_hashtags_input = gr.Textbox(
label="🏷️ Custom Hashtags (optional)",
placeholder="#AI #Innovation #Tech"
)
with gr.Row():
generate_button = gr.Button("✨ Generate Post", variant="primary", size="lg")
suggest_hashtags_button = gr.Button("πŸ’‘ Suggest Hashtags")
with gr.Column(scale=2):
output_box = gr.Textbox(
label="πŸ“„ Generated Post",
lines=25,
interactive=True,
elem_classes="output-text"
)
with gr.Row():
copy_button = gr.Button("πŸ“‹ Copy", size="sm")
export_button = gr.Button("πŸ’Ύ Export as .txt", size="sm")
with gr.Row():
copy_status = gr.Textbox(label="", interactive=False, show_label=False, lines=1)
export_file = gr.File(label="πŸ“₯ Download File", interactive=False, type="filepath")
# Tab 2: A/B Testing
with gr.Tab("πŸ”¬ A/B Testing"):
gr.Markdown("### Generate two versions of your post optimized for different strategies")
with gr.Row():
with gr.Column():
ab_topic = gr.Textbox(label="πŸ“ Topic", placeholder="Enter your topic...", lines=3)
with gr.Row():
ab_tone = gr.Dropdown(
["Professional", "Friendly", "Inspirational", "Analytical"],
label="🎭 Tone",
value="Professional"
)
ab_audience = gr.Dropdown(
["General", "C-Level Executives", "Managers", "Individual Contributors"],
label="🎯 Audience",
value="General"
)
ab_button = gr.Button("πŸ”¬ Generate A/B Versions", variant="primary")
with gr.Column():
ab_output = gr.Textbox(label="πŸ“Š A/B Test Results", lines=30, interactive=True)
# Tab 3: Schedule Optimizer
with gr.Tab("πŸ“… Schedule Optimizer"):
gr.Markdown("### Find the perfect time to post based on your industry and audience")
with gr.Row():
with gr.Column():
schedule_industry = gr.Textbox(
label="🏒 Your Industry",
placeholder="e.g., Technology, Marketing, Finance..."
)
schedule_location = gr.Dropdown(
["North America (EST)", "Europe (CET)", "Asia Pacific", "Global/Mixed"],
label="🌍 Primary Audience Location",
value="North America (EST)"
)
schedule_goal = gr.Dropdown(
["Maximum Reach", "Engagement (Comments/Shares)", "Lead Generation", "Thought Leadership"],
label="🎯 Primary Goal",
value="Maximum Reach"
)
schedule_button = gr.Button("⏰ Get Optimal Times", variant="primary")
with gr.Column():
schedule_output = gr.Textbox(label="πŸ“… Recommended Posting Schedule", lines=20)
# Tab 4: Competitor Analysis
with gr.Tab("πŸ” Competitor Analysis"):
gr.Markdown("### Analyze successful posts to understand what works")
with gr.Row():
with gr.Column():
competitor_post = gr.Textbox(
label="πŸ“ Paste Competitor's Post",
placeholder="Paste the successful post you want to analyze...",
lines=10
)
competitor_niche = gr.Textbox(
label="🎯 Your Niche/Industry",
placeholder="e.g., SaaS Marketing, Data Science..."
)
analyze_button = gr.Button("πŸ” Analyze Post", variant="primary")
with gr.Column():
competitor_output = gr.Textbox(label="πŸ“Š Analysis Results", lines=25)
# Tab 5: Image Suggestions
with gr.Tab("πŸ–ΌοΈ Image Suggestions"):
gr.Markdown("### Get AI-powered recommendations for visual content")
with gr.Row():
with gr.Column():
image_post = gr.Textbox(
label="πŸ“ Your Post Content",
placeholder="Paste your post here...",
lines=10
)
image_type = gr.Dropdown(
["Standard Post", "Story Post", "Carousel", "Article Cover"],
label="πŸ“„ Post Type",
value="Standard Post"
)
image_button = gr.Button("🎨 Get Image Suggestions", variant="primary")
with gr.Column():
image_output = gr.Textbox(label="πŸ–ΌοΈ Visual Recommendations", lines=25)
# Tab 6: Trend Analyzer
with gr.Tab("πŸ“ˆ Trend Analyzer"):
gr.Markdown("### Discover what's trending in your industry on LinkedIn")
with gr.Row():
with gr.Column():
trend_industry = gr.Textbox(
label="🏒 Industry",
placeholder="e.g., AI, Marketing, Fintech..."
)
trend_timeframe = gr.Dropdown(
["Last 7 days", "Last 30 days", "Last 3 months"],
label="⏰ Timeframe",
value="Last 30 days"
)
trend_button = gr.Button("πŸ“Š Analyze Trends", variant="primary")
with gr.Column():
trend_output = gr.Textbox(label="πŸ“ˆ Trending Topics & Insights", lines=25)
# Tab 7: Personal Branding
with gr.Tab("🎭 Personal Branding"):
gr.Markdown("### Create your unique brand voice for consistent LinkedIn presence")
with gr.Tabs():
with gr.Tab("Create Brand Voice"):
with gr.Row():
with gr.Column():
brand_name = gr.Textbox(label="πŸ‘€ Your Name", placeholder="John Doe")
brand_industry = gr.Textbox(label="🏒 Industry", placeholder="e.g., Digital Marketing")
brand_values = gr.Textbox(
label="πŸ’Ž Core Values",
placeholder="e.g., Innovation, Authenticity, Growth",
lines=2
)
brand_personality = gr.Textbox(
label="🎭 Personality Traits",
placeholder="e.g., Approachable, Data-driven, Creative",
lines=2
)
brand_expertise = gr.Textbox(
label="πŸŽ“ Key Expertise",
placeholder="e.g., Content Strategy, SEO, Brand Building",
lines=2
)
brand_create_button = gr.Button("✨ Create Brand Voice Guide", variant="primary")
with gr.Column():
brand_output = gr.Textbox(label="πŸ“‹ Your Brand Voice Guide", lines=30)
with gr.Tab("Apply Brand Voice"):
with gr.Row():
with gr.Column():
apply_post = gr.Textbox(
label="πŸ“ Post to Brand",
placeholder="Paste any post here to adapt it to your brand voice...",
lines=10
)
apply_guide = gr.Textbox(
label="πŸ“‹ Brand Guidelines (summary)",
placeholder="Paste key points from your brand guide...",
lines=5
)
apply_button = gr.Button("🎨 Apply Brand Voice", variant="primary")
with gr.Column():
apply_output = gr.Textbox(label="✨ Branded Post", lines=20)
# Tab 8: Rewrite Post
with gr.Tab("πŸ”„ Rewrite Post"):
with gr.Row():
with gr.Column():
original_post_input = gr.Textbox(
label="πŸ“ Paste Your Post",
placeholder="Paste your LinkedIn post here...",
lines=10
)
rewrite_instruction = gr.Textbox(
label="✏️ Rewrite Instruction",
placeholder="e.g., Make it more professional, Add storytelling, Shorten it...",
lines=3
)
rewrite_button = gr.Button("πŸ”„ Rewrite Post", variant="primary")
with gr.Column():
rewrite_output = gr.Textbox(
label="✨ Rewritten Post",
lines=15,
interactive=True
)
# Tab 9: Post History
with gr.Tab("πŸ“š Post History"):
gr.Markdown("### View and manage your generated posts")
with gr.Row():
with gr.Column(scale=2):
history_display = gr.Textbox(
label="πŸ“œ Recent Posts (Last 10)",
lines=30,
value=format_history(),
interactive=False
)
refresh_history_button = gr.Button("πŸ”„ Refresh History")
with gr.Column(scale=1):
gr.Markdown("### Load Post from History")
load_post_number = gr.Number(
label="Post Number",
value=1,
precision=0
)
load_button = gr.Button("πŸ“₯ Load Post")
loaded_post = gr.Textbox(label="Loaded Post", lines=15, interactive=True)
gr.Markdown("### Export Multiple Posts")
export_count = gr.Slider(
minimum=1,
maximum=10,
step=1,
value=5,
label="Number of posts to export"
)
export_all_button = gr.Button("πŸ’Ύ Export Package")
export_status = gr.Textbox(label="Export Status", lines=2)
export_package_file = gr.File(label="πŸ“₯ Download Package", interactive=False, type="filepath")
# Tab 10: Tips & Best Practices
with gr.Tab("πŸ’‘ Tips & Best Practices"):
gr.Markdown(
"""
## 🎯 LinkedIn Best Practices
### πŸ“ˆ Maximize Engagement:
- **Hook in first 2 lines**: Grab attention immediately
- **Use line breaks**: Make posts visually scannable
- **Include data/numbers**: Specific metrics build credibility
- **Add storytelling**: Personal experiences resonate
- **End with CTA**: Ask questions, request opinions
### βœ… Optimal Post Structure:
1. **Hook** (1-2 lines) - Stop the scroll
2. **Context/Story** (3-5 lines) - Build connection
3. **Key Points** (bullet points work well) - Deliver value
4. **Conclusion/Insight** (2-3 lines) - Tie it together
5. **CTA** (1 line + hashtags) - Drive action
### 🏷️ Hashtag Strategy:
- Use 3-5 hashtags maximum
- Mix popular (100K+ followers) and niche (10K-50K) hashtags
- Place at the end of post
- Research trending hashtags in your industry weekly
### πŸ“Š Best Times to Post:
- **Tuesday-Thursday**: 9-11 AM (highest engagement)
- **Wednesday**: Best overall day
- **Avoid**: Weekends for B2B, early mornings, late evenings
- **Test**: Your audience may have unique patterns
### πŸ’Ž Content Types That Work:
- **Personal stories**: Authentic experiences (highest engagement)
- **Industry insights**: Thought leadership
- **How-to guides**: Actionable advice
- **Data-driven posts**: Research and statistics
- **Controversial opinions**: Spark discussion (carefully!)
- **Lists**: Easy to scan, high shareability
- **Behind-the-scenes**: Show your process
### 🎨 Visual Content Tips:
- Posts with images get 2x more comments
- Carousel posts get 1.5x more reach
- Use high-quality, professional images
- Infographics perform exceptionally well
- Personal photos > stock photos
### πŸš€ Growth Hacks:
1. **Comment within first hour**: Boost your own post
2. **Engage before posting**: Warm up the algorithm
3. **Tag relevant people**: (2-3 max, only when appropriate)
4. **Post consistently**: 3-5x per week minimum
5. **Respond to every comment**: Within first 2 hours
6. **Use "see more" strategically**: Hook in first 2 lines
7. **Write for mobile**: Short paragraphs, more line breaks
### πŸ“ Optimal Lengths:
- **Standard posts**: 150-250 words (sweet spot: 200)
- **Long-form**: 1,300-2,000 words (for thought leadership)
- **Carousels**: 10-15 slides maximum
- **Threads**: 3-5 posts
### ⚠️ What to Avoid:
- External links (post in first comment instead)
- Too many hashtags (looks spammy)
- Generic content (be specific!)
- Overly promotional content
- Inconsistent posting (algorithm penalizes)
- Ignoring comments (kills engagement)
### πŸŽ“ Advanced Tips:
- Use the **"3-3-3 Rule"**: 3 posts/week, 3 comments on others' posts/day, 3 meaningful connections/day
- **Native video** gets 5x more engagement than YouTube links
- **Ask questions** at the end - increases comments by 50%
- **Use emojis strategically** - but not in excess
- **Write for skimmers**: Bullets, bold, line breaks
"""
)
# =========================
# Event Handlers
# =========================
# Generate Post
generate_button.click(
fn=generate_post,
inputs=[
topic_input,
tone_input,
audience_input,
post_type_input,
word_count_input,
num_variations_input,
custom_hashtags_input
],
outputs=output_box
)
# Suggest Hashtags
suggest_hashtags_button.click(
fn=lambda topic: generate_hashtag_suggestions(topic, 5),
inputs=topic_input,
outputs=custom_hashtags_input
)
# A/B Testing
ab_button.click(
fn=generate_ab_versions,
inputs=[ab_topic, ab_tone, ab_audience],
outputs=ab_output
)
# Schedule Optimizer
schedule_button.click(
fn=get_best_posting_times,
inputs=[schedule_industry, schedule_location, schedule_goal],
outputs=schedule_output
)
# Competitor Analysis
analyze_button.click(
fn=analyze_competitor_post,
inputs=[competitor_post, competitor_niche],
outputs=competitor_output
)
# Image Suggestions
image_button.click(
fn=suggest_images,
inputs=[image_post, image_type],
outputs=image_output
)
# Trend Analyzer
trend_button.click(
fn=analyze_linkedin_trends,
inputs=[trend_industry, trend_timeframe],
outputs=trend_output
)
# Personal Branding
brand_create_button.click(
fn=create_brand_voice,
inputs=[brand_name, brand_industry, brand_values, brand_personality, brand_expertise],
outputs=brand_output
)
apply_button.click(
fn=apply_brand_voice,
inputs=[apply_post, apply_guide],
outputs=apply_output
)
# Rewrite Post
rewrite_button.click(
fn=rewrite_post,
inputs=[original_post_input, rewrite_instruction],
outputs=rewrite_output
)
# Post History
refresh_history_button.click(
fn=format_history,
inputs=[],
outputs=history_display
)
load_button.click(
fn=get_post_from_history,
inputs=load_post_number,
outputs=loaded_post
)
# Export History Package - FIXED
export_all_button.click(
fn=export_history_package,
inputs=export_count,
outputs=[export_package_file, export_status]
)
# Copy to Clipboard
copy_js = """
async function() {
const textArea = document.querySelector('.output-text textarea');
if (textArea && textArea.value) {
try {
await navigator.clipboard.writeText(textArea.value);
return "βœ… Copied successfully!";
} catch (err) {
textArea.select();
document.execCommand('copy');
return "βœ… Copied successfully!";
}
}
return "❌ Nothing to copy! Generate a post first.";
}
"""
copy_button.click(
fn=None,
inputs=None,
outputs=copy_status,
js=copy_js
)
# Export Current Post - FIXED
export_button.click(
fn=export_current_post,
inputs=[output_box],
outputs=[export_file, copy_status]
)
# Launch the application
print("\n" + "="*80)
print("πŸš€ LAUNCHING LINKEDIN AI WRITER PRO - ULTIMATE EDITION")
print("="*80 + "\n")
demo.launch(share=True, debug=True)