# !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)