kapildew18's picture
Update app.py
be633a1 verified
Raw
History Blame Contribute Delete
26.7 kB
"""
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
)