Spaces:
Sleeping
Sleeping
| """ | |
| Enhanced LinkedIn Post Generator | |
| Powered by Google Gemini AI | |
| Features: | |
| - Multiple post formats (Standard, Story, List, Question) | |
| - Industry-specific templates | |
| - Post analytics predictions | |
| - Multiple language support | |
| - Batch generation | |
| - Advanced customization options | |
| Requirements: | |
| google-generativeai==0.3.2 | |
| gradio==4.20.0 | |
| requests==2.31.0 | |
| """ | |
| import gradio as gr | |
| import google.generativeai as genai | |
| import os | |
| import json | |
| import re | |
| from datetime import datetime | |
| from typing import List, Dict, Tuple, Optional | |
| # --- Configuration --- | |
| MODEL = "gemini-2.5-flash" | |
| SUPPORTED_LANGUAGES = { | |
| "English": "en", | |
| "Spanish": "es", | |
| "French": "fr", | |
| "German": "de", | |
| "Portuguese": "pt", | |
| "Italian": "it", | |
| "Dutch": "nl", | |
| "Japanese": "ja", | |
| "Korean": "ko", | |
| "Chinese": "zh" | |
| } | |
| class EnhancedLinkedInGenerator: | |
| def __init__(self, api_key=None): | |
| self.api_key = api_key | |
| self.model = None | |
| if api_key: | |
| self.configure_api(api_key) | |
| def configure_api(self, api_key: str) -> bool: | |
| """Configure Gemini API with provided key""" | |
| try: | |
| genai.configure(api_key=api_key) | |
| self.model = genai.GenerativeModel(MODEL) | |
| self.api_key = api_key | |
| return True | |
| except Exception as e: | |
| print(f"API Configuration Error: {e}") | |
| return False | |
| def extract_response_text(self, response) -> str: | |
| """Robust response text extraction for various Gemini API response formats""" | |
| try: | |
| # Method 1: Simple text accessor (most common) | |
| if hasattr(response, 'text') and response.text: | |
| return response.text | |
| # Method 2: Candidates with parts | |
| if hasattr(response, 'candidates') and response.candidates: | |
| candidate = response.candidates[0] | |
| if hasattr(candidate, 'content') and candidate.content: | |
| if hasattr(candidate.content, 'parts') and candidate.content.parts: | |
| return candidate.content.parts[0].text | |
| # Method 3: Direct parts access | |
| if hasattr(response, 'parts') and response.parts: | |
| return response.parts[0].text | |
| return "β Error: Unable to extract text from Gemini response." | |
| except Exception as e: | |
| return f"β Error parsing response: {str(e)}" | |
| def get_industry_context(self, industry: str) -> str: | |
| """Get industry-specific context and terminology""" | |
| industry_contexts = { | |
| "Technology": "Use tech terminology, mention innovation, digital transformation, and emerging technologies", | |
| "Healthcare": "Focus on patient care, medical advances, healthcare accessibility, and wellness", | |
| "Finance": "Emphasize financial literacy, market trends, investment strategies, and economic insights", | |
| "Education": "Highlight learning methodologies, educational technology, skill development, and knowledge sharing", | |
| "Marketing": "Discuss brand strategies, customer engagement, digital marketing trends, and creative campaigns", | |
| "Sales": "Focus on relationship building, sales techniques, customer success, and revenue growth", | |
| "HR": "Emphasize talent management, workplace culture, employee engagement, and professional development", | |
| "Consulting": "Highlight problem-solving, strategic thinking, client success stories, and industry expertise", | |
| "Real Estate": "Focus on market trends, property investment, client relationships, and industry insights", | |
| "Retail": "Discuss customer experience, retail innovation, market trends, and brand loyalty", | |
| "Manufacturing": "Emphasize operational efficiency, quality control, supply chain, and industrial innovation", | |
| "Non-Profit": "Focus on social impact, community engagement, fundraising, and mission-driven work" | |
| } | |
| return industry_contexts.get(industry, "Use professional language appropriate for your industry") | |
| def get_post_template(self, post_format: str, tone: str) -> str: | |
| """Get format-specific templates for different post types""" | |
| templates = { | |
| "Standard": f""" | |
| Create a {tone} LinkedIn post with this structure: | |
| 1. **Hook** (1-2 sentences): Start with an attention-grabbing statement or question | |
| 2. **Body** (2-3 paragraphs): Develop the main points with specific examples | |
| 3. **Call to Action**: End with engagement-driving question or action request | |
| 4. **Hashtags**: Include 3-5 relevant hashtags at the end | |
| """, | |
| "Story": f""" | |
| Create a {tone} LinkedIn story post with this structure: | |
| 1. **Opening** (1 sentence): Set the scene with "Recently..." or "Last week..." | |
| 2. **Challenge/Situation** (1-2 sentences): Describe the problem or situation | |
| 3. **Action/Solution** (2-3 sentences): What was done to address it | |
| 4. **Outcome/Lesson** (1-2 sentences): Results and key takeaway | |
| 5. **Question**: Ask readers about their similar experiences | |
| 6. **Hashtags**: Include 3-5 relevant hashtags | |
| """, | |
| "List": f""" | |
| Create a {tone} LinkedIn list post with this structure: | |
| 1. **Introduction** (1-2 sentences): Introduce the list topic | |
| 2. **List Items** (5-7 items): Each with brief explanation | |
| β’ Use bullet points or numbers | |
| β’ Keep each point concise but valuable | |
| 3. **Conclusion** (1 sentence): Summarize the value | |
| 4. **Engagement**: Ask which point resonates most | |
| 5. **Hashtags**: Include 3-5 relevant hashtags | |
| """, | |
| "Question": f""" | |
| Create a {tone} LinkedIn question post with this structure: | |
| 1. **Context** (2-3 sentences): Provide background for the question | |
| 2. **Main Question** (1 sentence): Clear, thought-provoking question | |
| 3. **Sub-questions** (2-3 follow-up questions): Guide the discussion | |
| 4. **Your Take** (1-2 sentences): Share your initial thoughts | |
| 5. **Call to Participate**: Encourage comments and discussion | |
| 6. **Hashtags**: Include 3-5 relevant hashtags | |
| """, | |
| "Achievement": f""" | |
| Create a {tone} LinkedIn achievement post with this structure: | |
| 1. **Announcement** (1 sentence): Share the achievement | |
| 2. **Journey** (2-3 sentences): Brief story of how you got there | |
| 3. **Gratitude** (1-2 sentences): Thank people who helped | |
| 4. **Learning** (1-2 sentences): What you learned along the way | |
| 5. **Forward Look**: What's next or how others can achieve similar success | |
| 6. **Hashtags**: Include 3-5 relevant hashtags | |
| """ | |
| } | |
| return templates.get(post_format, templates["Standard"]) | |
| def generate_post(self, | |
| topic: str, | |
| audience: str, | |
| key_points: str, | |
| tone: str, | |
| post_format: str, | |
| industry: str, | |
| language: str, | |
| api_key: str, | |
| include_emoji: bool = True, | |
| post_length: str = "Medium") -> str: | |
| """Generate enhanced LinkedIn post with advanced options""" | |
| # Validate inputs | |
| if not all([topic.strip(), audience.strip(), key_points.strip()]): | |
| return "β Error: Please fill in all required fields (Topic, Audience, Key Points)." | |
| if not api_key.strip(): | |
| return "β Error: Please provide your Gemini API key." | |
| # Configure API | |
| if not self.configure_api(api_key): | |
| return "β Error: Invalid API key. Please check your Gemini API key and try again." | |
| # Format key points | |
| formatted_key_points = "\n".join([f"- {line.strip()}" for line in key_points.split("\n") if line.strip()]) | |
| # Get industry context and post template | |
| industry_context = self.get_industry_context(industry) | |
| post_template = self.get_post_template(post_format, tone) | |
| # Determine post length guidance | |
| length_guidance = { | |
| "Short": "Keep the post concise (100-150 words). Perfect for quick insights.", | |
| "Medium": "Create a medium-length post (150-250 words). Balanced detail and readability.", | |
| "Long": "Write a comprehensive post (250-400 words). Detailed and informative." | |
| } | |
| # Build comprehensive prompt | |
| prompt = f""" | |
| You are an expert LinkedIn content strategist and copywriter with deep understanding of professional social media engagement. | |
| **Your Task:** Create a high-quality LinkedIn post based on the specifications below. | |
| **Post Specifications:** | |
| - **Topic:** {topic} | |
| - **Target Audience:** {audience} | |
| - **Post Format:** {post_format} | |
| - **Tone:** {tone} | |
| - **Industry:** {industry} | |
| - **Language:** {language} | |
| - **Length:** {length_guidance[post_length]} | |
| - **Include Emojis:** {include_emoji} | |
| **Industry Context:** {industry_context} | |
| **Key Points to Include:** | |
| {formatted_key_points} | |
| **Post Structure Guidelines:** | |
| {post_template} | |
| **Additional Requirements:** | |
| 1. **Professional Quality:** Ensure content is polished and error-free | |
| 2. **Engagement Optimization:** Use techniques that encourage likes, comments, and shares | |
| 3. **Value-First:** Every sentence should provide value to the reader | |
| 4. **Authenticity:** Make it sound natural and genuine, not overly promotional | |
| 5. **Visual Appeal:** {"Use relevant emojis strategically to enhance readability" if include_emoji else "Do not use emojis"} | |
| 6. **Language:** Write entirely in {language} | |
| 7. **Hashtag Strategy:** Choose hashtags that are popular but not oversaturated | |
| **Engagement Best Practices:** | |
| - Start with a hook that makes people want to read more | |
| - Use short paragraphs for better mobile readability | |
| - Include specific examples or data when possible | |
| - End with a question or call-to-action that encourages responses | |
| - Make it scannable with bullet points or line breaks | |
| Generate the complete LinkedIn post now: | |
| """ | |
| try: | |
| # Generate the post | |
| response = self.model.generate_content( | |
| prompt, | |
| generation_config=genai.types.GenerationConfig( | |
| temperature=0.7, | |
| top_p=0.9, | |
| max_output_tokens=1500, | |
| ) | |
| ) | |
| # Extract response text | |
| post_content = self.extract_response_text(response) | |
| if post_content.startswith("β"): | |
| return post_content | |
| # Add metadata | |
| metadata = f""" | |
| **Post Analytics Prediction:** | |
| - **Estimated Reach:** {self.predict_reach(topic, audience, tone)} | |
| - **Best Posting Time:** {self.suggest_posting_time(audience)} | |
| - **Engagement Potential:** {self.predict_engagement(post_format, tone)} | |
| --- | |
| *Generated on {datetime.now().strftime("%Y-%m-%d at %H:%M")} using Enhanced LinkedIn Post Generator* | |
| """ | |
| return f"{post_content}\n\n{metadata}" | |
| except Exception as e: | |
| return f"β Error generating post: {str(e)}" | |
| def predict_reach(self, topic: str, audience: str, tone: str) -> str: | |
| """Predict potential reach based on topic and audience""" | |
| # Simplified prediction logic | |
| if "AI" in topic or "technology" in topic.lower(): | |
| return "High (5,000-15,000 impressions)" | |
| elif "business" in topic.lower() or "leadership" in topic.lower(): | |
| return "Medium-High (3,000-10,000 impressions)" | |
| else: | |
| return "Medium (1,000-5,000 impressions)" | |
| def suggest_posting_time(self, audience: str) -> str: | |
| """Suggest optimal posting times based on audience""" | |
| if "executive" in audience.lower() or "ceo" in audience.lower(): | |
| return "Tuesday-Thursday, 8-9 AM or 12-1 PM" | |
| elif "developer" in audience.lower() or "engineer" in audience.lower(): | |
| return "Tuesday-Wednesday, 9-10 AM or 2-3 PM" | |
| else: | |
| return "Tuesday-Thursday, 9 AM-12 PM" | |
| def predict_engagement(self, post_format: str, tone: str) -> str: | |
| """Predict engagement potential""" | |
| engagement_scores = { | |
| "Question": "High", | |
| "Story": "High", | |
| "List": "Medium-High", | |
| "Standard": "Medium", | |
| "Achievement": "Medium" | |
| } | |
| return f"{engagement_scores.get(post_format, 'Medium')} engagement expected" | |
| def generate_multiple_posts(self, | |
| topic: str, | |
| audience: str, | |
| key_points: str, | |
| api_key: str, | |
| count: int = 3) -> str: | |
| """Generate multiple post variations""" | |
| formats = ["Standard", "Story", "Question"] | |
| tones = ["Professional", "Inspirational", "Conversational"] | |
| results = [] | |
| for i in range(min(count, 3)): | |
| post = self.generate_post( | |
| topic=topic, | |
| audience=audience, | |
| key_points=key_points, | |
| tone=tones[i], | |
| post_format=formats[i], | |
| industry="Technology", | |
| language="English", | |
| api_key=api_key, | |
| include_emoji=True, | |
| post_length="Medium" | |
| ) | |
| results.append(f"**Variation {i+1} ({formats[i]} - {tones[i]}):**\n{post}\n\n{'='*50}\n") | |
| return "\n".join(results) | |
| # Initialize generator | |
| generator = EnhancedLinkedInGenerator() | |
| def save_post_to_file(post_content: str, topic: str) -> str: | |
| """Save generated post to downloadable file""" | |
| if not post_content or post_content.startswith("β"): | |
| return None | |
| timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | |
| filename = f"linkedin_post_{topic.replace(' ', '_')}_{timestamp}.txt" | |
| with open(filename, 'w', encoding='utf-8') as f: | |
| f.write(post_content) | |
| return filename | |
| # Create the enhanced Gradio interface | |
| with gr.Blocks( | |
| theme=gr.themes.Soft(), | |
| title="Enhanced LinkedIn Post Generator - Powered by Google Gemini AI", | |
| css=""" | |
| .main-header { text-align: center; margin-bottom: 2rem; } | |
| .feature-box { background: linear-gradient(45deg, #667eea, #764ba2); padding: 1rem; border-radius: 8px; color: white; margin: 1rem 0; } | |
| .pro-tip { background: #f0f9ff; padding: 1rem; border-left: 4px solid #3b82f6; margin: 1rem 0; } | |
| """ | |
| ) as demo: | |
| # Header | |
| gr.Markdown(""" | |
| <div class="main-header"> | |
| <h1>π Enhanced LinkedIn Post Generator</h1> | |
| <h3>Powered by Google Gemini AI</h3> | |
| <p>Create professional, engaging LinkedIn content with advanced AI assistance</p> | |
| </div> | |
| """, elem_classes=["main-header"]) | |
| # Feature highlights | |
| gr.Markdown(""" | |
| <div class="feature-box"> | |
| <h4>β¨ Advanced Features</h4> | |
| <ul> | |
| <li>π― Multiple post formats (Standard, Story, List, Question, Achievement)</li> | |
| <li>π’ Industry-specific templates and terminology</li> | |
| <li>π Multi-language support (10 languages)</li> | |
| <li>π Post analytics predictions</li> | |
| <li>π¨ Customizable tone and length options</li> | |
| <li>π± Mobile-optimized formatting</li> | |
| </ul> | |
| </div> | |
| """, elem_classes=["feature-box"]) | |
| with gr.Tabs(): | |
| # Single Post Generation Tab | |
| with gr.TabItem("π Generate Single Post"): | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| gr.Markdown("## π API Configuration") | |
| api_key_input = gr.Textbox( | |
| label="Gemini API Key", | |
| placeholder="Enter your Google Gemini API key", | |
| type="password", | |
| info="Get your free API key from: https://aistudio.google.com/app/apikey" | |
| ) | |
| gr.Markdown("## π Basic Information") | |
| topic_input = gr.Textbox( | |
| label="Post Topic *", | |
| placeholder="e.g., 'The Future of Remote Work', 'AI in Healthcare', 'Leadership Lessons'", | |
| lines=1 | |
| ) | |
| audience_input = gr.Textbox( | |
| label="Target Audience *", | |
| placeholder="e.g., 'Software Engineers and Tech Leaders', 'Healthcare Professionals', 'Marketing Executives'", | |
| lines=2 | |
| ) | |
| key_points_input = gr.Textbox( | |
| label="Key Points to Cover *", | |
| placeholder="Enter one key point per line:\n- Main insight or benefit\n- Supporting evidence or example\n- Personal experience or tip\n- Future implications or next steps", | |
| lines=6 | |
| ) | |
| gr.Markdown("## π¨ Customization Options") | |
| with gr.Row(): | |
| tone_input = gr.Dropdown( | |
| label="Tone of Voice", | |
| choices=[ | |
| "Professional", "Inspirational", "Conversational", | |
| "Thought-provoking", "Educational", "Enthusiastic", | |
| "Analytical", "Motivational", "Friendly", "Authoritative" | |
| ], | |
| value="Professional" | |
| ) | |
| post_format_input = gr.Dropdown( | |
| label="Post Format", | |
| choices=["Standard", "Story", "List", "Question", "Achievement"], | |
| value="Standard", | |
| info="Choose the structure that best fits your content" | |
| ) | |
| with gr.Row(): | |
| industry_input = gr.Dropdown( | |
| label="Industry", | |
| choices=[ | |
| "Technology", "Healthcare", "Finance", "Education", | |
| "Marketing", "Sales", "HR", "Consulting", | |
| "Real Estate", "Retail", "Manufacturing", "Non-Profit" | |
| ], | |
| value="Technology" | |
| ) | |
| language_input = gr.Dropdown( | |
| label="Language", | |
| choices=list(SUPPORTED_LANGUAGES.keys()), | |
| value="English" | |
| ) | |
| with gr.Row(): | |
| post_length_input = gr.Dropdown( | |
| label="Post Length", | |
| choices=["Short", "Medium", "Long"], | |
| value="Medium", | |
| info="Short: 100-150 words, Medium: 150-250 words, Long: 250-400 words" | |
| ) | |
| include_emoji_input = gr.Checkbox( | |
| label="Include Emojis", | |
| value=True, | |
| info="Add emojis to enhance readability and engagement" | |
| ) | |
| generate_button = gr.Button( | |
| "π Generate LinkedIn Post", | |
| variant="primary", | |
| size="lg" | |
| ) | |
| with gr.Column(scale=3): | |
| gr.Markdown("## π Generated Content") | |
| output_post = gr.Markdown( | |
| label="Your LinkedIn Post", | |
| value="Your AI-generated LinkedIn post will appear here...", | |
| show_copy_button=True | |
| ) | |
| with gr.Row(): | |
| download_btn = gr.DownloadButton( | |
| "πΎ Download Post", | |
| size="sm", | |
| variant="secondary", | |
| visible=False | |
| ) | |
| regenerate_btn = gr.Button( | |
| "π Regenerate with Same Settings", | |
| size="sm", | |
| variant="secondary" | |
| ) | |
| # Batch Generation Tab | |
| with gr.TabItem("π Generate Multiple Variations"): | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| gr.Markdown("## π Batch Generation") | |
| gr.Markdown("Generate 3 different variations of your post with different formats and tones.") | |
| batch_api_key = gr.Textbox( | |
| label="Gemini API Key", | |
| placeholder="Enter your Google Gemini API key", | |
| type="password" | |
| ) | |
| batch_topic = gr.Textbox( | |
| label="Post Topic", | |
| placeholder="e.g., 'Digital Transformation in Healthcare'" | |
| ) | |
| batch_audience = gr.Textbox( | |
| label="Target Audience", | |
| placeholder="e.g., 'Healthcare IT Directors and Medical Professionals'", | |
| lines=2 | |
| ) | |
| batch_key_points = gr.Textbox( | |
| label="Key Points", | |
| placeholder="Enter key points, one per line", | |
| lines=5 | |
| ) | |
| batch_generate_btn = gr.Button( | |
| "π― Generate 3 Variations", | |
| variant="primary" | |
| ) | |
| with gr.Column(scale=2): | |
| batch_output = gr.Markdown( | |
| label="Post Variations", | |
| value="Multiple post variations will appear here...", | |
| show_copy_button=True | |
| ) | |
| # Pro Tips Section | |
| gr.Markdown(""" | |
| <div class="pro-tip"> | |
| <h4>π‘ Pro Tips for Better LinkedIn Posts</h4> | |
| <ul> | |
| <li><strong>Hook First:</strong> Your first sentence determines if people read the rest</li> | |
| <li><strong>Value-Driven:</strong> Every post should provide clear value to your audience</li> | |
| <li><strong>Story Format:</strong> Stories get 30x more engagement than standard posts</li> | |
| <li><strong>Question Ending:</strong> Always end with a question to drive comments</li> | |
| <li><strong>Optimal Length:</strong> 150-250 words perform best for engagement</li> | |
| <li><strong>Posting Time:</strong> Tuesday-Thursday, 8 AM-12 PM for best reach</li> | |
| <li><strong>Hashtag Strategy:</strong> Use 3-5 relevant hashtags, mix popular and niche</li> | |
| </ul> | |
| </div> | |
| """, elem_classes=["pro-tip"]) | |
| # Footer | |
| gr.Markdown(""" | |
| --- | |
| ### π Getting Started | |
| 1. **Get Your API Key:** Visit [Google AI Studio](https://aistudio.google.com/app/apikey) to get your free Gemini API key | |
| 2. **Choose Your Format:** Select the post format that best matches your content type | |
| 3. **Customize Settings:** Adjust tone, industry, and length to match your brand voice | |
| 4. **Generate & Refine:** Create your post and use the regenerate button for variations | |
| **API Usage:** Each post generation uses ~1,000-1,500 tokens. The free tier includes 60 requests per minute. | |
| *Built with β€οΈ using Google Gemini AI and Gradio* | |
| """) | |
| # Event handlers | |
| def generate_and_prepare_download(topic, audience, key_points, tone, post_format, | |
| industry, language, post_length, include_emoji, api_key): | |
| # Generate post | |
| post = generator.generate_post( | |
| topic=topic, | |
| audience=audience, | |
| key_points=key_points, | |
| tone=tone, | |
| post_format=post_format, | |
| industry=industry, | |
| language=language, | |
| api_key=api_key, | |
| include_emoji=include_emoji, | |
| post_length=post_length | |
| ) | |
| # Prepare download | |
| if not post.startswith("β") and topic.strip(): | |
| filename = save_post_to_file(post, topic) | |
| return post, gr.DownloadButton("πΎ Download Post", value=filename, visible=True) | |
| else: | |
| return post, gr.DownloadButton("πΎ Download Post", visible=False) | |
| def generate_batch_posts(topic, audience, key_points, api_key): | |
| if not api_key.strip(): | |
| return "β Error: Please provide your Gemini API key." | |
| return generator.generate_multiple_posts(topic, audience, key_points, api_key, 3) | |
| # Connect event handlers | |
| generate_button.click( | |
| fn=generate_and_prepare_download, | |
| inputs=[topic_input, audience_input, key_points_input, tone_input, | |
| post_format_input, industry_input, language_input, | |
| post_length_input, include_emoji_input, api_key_input], | |
| outputs=[output_post, download_btn] | |
| ) | |
| regenerate_btn.click( | |
| fn=generate_and_prepare_download, | |
| inputs=[topic_input, audience_input, key_points_input, tone_input, | |
| post_format_input, industry_input, language_input, | |
| post_length_input, include_emoji_input, api_key_input], | |
| outputs=[output_post, download_btn] | |
| ) | |
| batch_generate_btn.click( | |
| fn=generate_batch_posts, | |
| inputs=[batch_topic, batch_audience, batch_key_points, batch_api_key], | |
| outputs=[batch_output] | |
| ) | |
| # Launch configuration | |
| if __name__ == "__main__": | |
| print("π Launching Enhanced LinkedIn Post Generator...") | |
| print("β¨ Powered by Google Gemini AI") | |
| print("π Advanced Features Enabled") | |
| print("π Get your API key: https://aistudio.google.com/app/apikey") | |
| print() | |
| # Cloud-friendly launch (FIXED) | |
| demo.launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| share=False, | |
| show_error=True | |
| ) | |