ethimar / app.py
Ozgur Unlu
small changes
9fb1b7d
raw
history blame
14.9 kB
import gradio as gr
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
import nltk
from datetime import datetime, timedelta
import requests
from bs4 import BeautifulSoup
# Download required NLTK data
try:
nltk.data.find('tokenizers/punkt')
except LookupError:
nltk.download('punkt')
# Global variables to cache models
CACHED_MODELS = {}
# Initialize models and tokenizers
def load_models():
global CACHED_MODELS
if CACHED_MODELS:
return (
CACHED_MODELS['generator_tokenizer'],
CACHED_MODELS['generator'],
CACHED_MODELS['sentiment_analyzer'],
CACHED_MODELS['content_checker']
)
try:
# Use GPT-2 instead of DistilGPT-2
generator_model = "gpt2"
generator_tokenizer = AutoTokenizer.from_pretrained(generator_model)
generator = AutoModelForCausalLM.from_pretrained(generator_model)
# Sentiment analysis
sentiment_analyzer = pipeline(
"sentiment-analysis",
model="finiteautomata/bertweet-base-sentiment-analysis"
)
# Content safety checker
content_checker = pipeline(
"text-classification",
model="facebook/roberta-hate-speech-dynabench-r4-target"
)
# Cache the models
CACHED_MODELS['generator_tokenizer'] = generator_tokenizer
CACHED_MODELS['generator'] = generator
CACHED_MODELS['sentiment_analyzer'] = sentiment_analyzer
CACHED_MODELS['content_checker'] = content_checker
return generator_tokenizer, generator, sentiment_analyzer, content_checker
except Exception as e:
print(f"Error loading models: {str(e)}")
raise
def generate_content(
product_name,
product_description,
target_audience,
key_features,
unique_benefits,
platform,
tone,
generator_tokenizer,
generator,
sentiment_analyzer,
content_checker
):
char_limit = 280 if platform == "Twitter" else 500
# Split features and benefits into lists
features = [f.strip() for f in key_features.split(',')]
benefits = [b.strip() for b in unique_benefits.split(',')]
# Expanded intro phrases for each tone
intro_phrases = {
'professional': [
f"Introducing {product_name}:",
f"Discover {product_name}:",
f"Meet {product_name}:",
f"Presenting {product_name}:",
f"Announcing {product_name}:",
f"Experience {product_name}:",
f"Elevate your life with {product_name}:",
],
'casual': [
f"Check out {product_name}!",
f"Say hello to {product_name}!",
f"Get ready for {product_name}!",
f"You'll love {product_name}!",
f"Looking for something special? Try {product_name}!",
f"Meet your new favorite: {product_name}!",
f"Game-changer alert: {product_name} is here!",
],
'friendly': [
f"We're excited to share {product_name} with you!",
f"You'll love what {product_name} can do!",
f"Let {product_name} transform your day!",
f"Ready to discover {product_name}?",
f"Here's why you'll love {product_name}:",
f"Make every day better with {product_name}!",
f"Transform your experience with {product_name}!",
]
}
# Description connectors
description_connectors = [
f" - {product_description}",
f": {product_description}",
f"! {product_description}",
f", {product_description}",
f". {product_description}",
]
# Feature introduction phrases
feature_intros = [
"Featuring",
"With",
"Including",
"Equipped with",
"Powered by",
"Designed with",
"Built with",
"Offering",
]
# Benefit connectors
benefit_connectors = [
"Experience",
"Enjoy",
"Benefit from",
"Take advantage of",
"Discover",
"Appreciate",
"Make the most of",
]
# Target audience phrases
audience_phrases = [
f"Perfect for {target_audience}",
f"Ideal for {target_audience}",
f"Designed for {target_audience}",
f"Made specially for {target_audience}",
f"Tailored for {target_audience}",
f"Created with {target_audience} in mind",
]
# Call-to-action phrases
cta_phrases = {
'Twitter': [
"Learn more today!",
"Discover more β†’",
"Get yours now!",
"Visit our website!",
"Join us today!",
"Transform your life today!",
"Start your journey!",
],
'Instagram': [
f"\n\n#{product_name.replace(' ', '')}",
f"\n\nLearn more - Link in bio! #{product_name.replace(' ', '')}",
f"\n\nDiscover more ↗️ #{product_name.replace(' ', '')}",
f"\n\nTap link to learn more! #{product_name.replace(' ', '')}",
]
}
import random
def create_post():
# Select tone
selected_tone = tone.lower() if tone.lower() in intro_phrases else 'professional'
# Random structure selection (1-4)
structure = random.randint(1, 4)
if structure == 1:
# Standard structure
post = random.choice(intro_phrases[selected_tone])
post += random.choice(description_connectors)
feature = random.choice(features)
benefit = random.choice(benefits)
if len(post) + len(feature) + len(benefit) + 20 < char_limit:
post += f" {random.choice(feature_intros)} {feature}."
post += f" {random.choice(benefit_connectors)} {benefit}."
elif structure == 2:
# Benefit-first structure
benefit = random.choice(benefits)
post = f"Ready to {benefit.lower()}? "
post += random.choice(intro_phrases[selected_tone])
post += random.choice(description_connectors)
if len(post) + 30 < char_limit:
feature = random.choice(features)
post += f" {random.choice(feature_intros)} {feature}."
elif structure == 3:
# Question-based structure
post = f"Looking for {product_description.lower()}? "
post += random.choice(intro_phrases[selected_tone]).replace(':', '!')
feature = random.choice(features)
benefit = random.choice(benefits)
if len(post) + len(feature) + len(benefit) + 20 < char_limit:
post += f" {random.choice(feature_intros)} {feature}."
post += f" {benefit}."
else:
# Feature-focused structure
feature = random.choice(features)
post = f"From {feature} to {random.choice(benefits).lower()}, "
post += f"{product_name} has it all! "
post += product_description
# Add target audience if space allows
if len(post) + 50 < char_limit:
post += f" {random.choice(audience_phrases)}."
# Add call to action
if platform == "Twitter":
if len(post) + 30 < char_limit:
post += f" {random.choice(cta_phrases['Twitter'])}"
else:
if len(post) + 50 < char_limit:
post += random.choice(cta_phrases['Instagram'])
return post.strip()
try:
# Generate multiple versions
posts = [create_post() for _ in range(2)]
filtered_content = []
for post in posts:
# Verify length
if len(post) > char_limit:
post = post[:char_limit-3] + "..."
# Check sentiment and safety
try:
sentiment = sentiment_analyzer(post)[0]
safety_check = content_checker(post)[0]
filtered_content.append({
'text': post,
'sentiment': sentiment['label'],
'safety_score': f"{float(safety_check.get('score', 0)):.2f}"
})
except Exception as e:
print(f"Error in content analysis: {str(e)}")
continue
return filtered_content if filtered_content else [{
'text': create_post(),
'sentiment': 'positive',
'safety_score': '1.00'
}]
except Exception as e:
print(f"Error in content generation: {str(e)}")
return [{
'text': f"Introducing {product_name}: {product_description[:100]}... Learn more!",
'sentiment': 'neutral',
'safety_score': '1.00'
}]
def create_interface():
print("Loading models...")
generator_tokenizer, generator, sentiment_analyzer, content_checker = load_models()
print("Models loaded successfully!")
def fill_sample_data():
return [
"EcoBottle",
"Sustainable water bottle made from recycled ocean plastic",
"Environmentally conscious young professionals",
"100% recycled materials, Insulated design, Leak-proof",
"Helps clean oceans, Keeps drinks cold for 24 hours",
"Twitter",
"professional"
]
def clear_form():
return [""] * 7 # Returns empty strings for all 7 input fields
import time
def process_input_with_loading(
product_name,
product_description,
target_audience,
key_features,
unique_benefits,
platform,
tone,
progress=gr.Progress()
):
# Initial loading message
features_list = """⚑ While I generate your content, here's what I can do:
πŸ“ Generate multiple unique marketing messages
🎯 Adapt content for different platforms
πŸ” Ensure ethical content generation
πŸ“Š Analyze sentiment and safety
✨ Create platform-specific formatting
Processing your request..."""
yield features_list + "\n\n⏳ Starting generation..."
time.sleep(1)
# Update message with steps
steps = [
"Loading language models...",
"Analyzing product information...",
"Generating content variations...",
"Checking content safety...",
"Finalizing output..."
]
for i, step in enumerate(steps, 1):
progress(i/len(steps))
yield features_list + f"\n\n⏳ {step}"
time.sleep(1)
# Generate actual content
try:
results = generate_content(
product_name,
product_description,
target_audience,
key_features,
unique_benefits,
platform,
tone,
generator_tokenizer,
generator,
sentiment_analyzer,
content_checker
)
output = "🎯 Generated Marketing Content:\n\n"
for i, content in enumerate(results, 1):
output += f"Version {i}:\n"
output += f"πŸ“ Content: {content['text']}\n"
output += f"😊 Sentiment: {content['sentiment']}\n"
output += f"βœ… Safety Score: {content['safety_score']}\n"
output += "-" * 50 + "\n"
yield output
except Exception as e:
yield f"An error occurred: {str(e)}"
# Create the interface with blocks for custom layout
with gr.Blocks(theme=gr.themes.Default()) as demo:
gr.Markdown("# Ethimar - AI Marketing Content Generator")
gr.Markdown("Generate ethical marketing content with AI-powered insights.\n⏳ Note: First generation might take 3-5 minutes due to model loading. Subsequent generations will be faster!")
# Sample data button with custom styling
with gr.Row():
fill_button = gr.Button(
"Fill the form with sample data",
variant="primary",
size="sm",
scale=0.2
)
# Main content area with two columns
with gr.Row():
# Left column - Input form
with gr.Column(scale=1):
product_name = gr.Textbox(label="Product Name", placeholder="Enter product name")
product_description = gr.Textbox(label="Product Description", lines=3, placeholder="Brief description of your product")
target_audience = gr.Textbox(label="Target Audience", placeholder="Who is this product for?")
key_features = gr.Textbox(label="Key Features", lines=2, placeholder="Main features of your product")
unique_benefits = gr.Textbox(label="Unique Benefits", lines=2, placeholder="What makes your product special?")
platform = gr.Radio(
choices=["Twitter", "Instagram"],
label="Platform",
value="Twitter"
)
tone = gr.Textbox(label="Tone", placeholder="e.g., professional, casual, friendly")
# Buttons row at the bottom of the form
with gr.Row():
with gr.Column(scale=2):
submit_button = gr.Button("Generate Content", variant="primary", scale=1)
with gr.Column(scale=1):
clear_button = gr.Button("Clear Form", variant="secondary", scale=1)
# Right column - Output
with gr.Column(scale=1):
output = gr.Textbox(
label="Generated Content",
lines=12,
value="✨ Enter your product details and click 'Generate Content' to start!"
)
# Connect all buttons to functions
input_components = [
product_name,
product_description,
target_audience,
key_features,
unique_benefits,
platform,
tone
]
fill_button.click(
fn=fill_sample_data,
outputs=input_components
)
submit_button.click(
fn=process_input_with_loading,
inputs=input_components,
outputs=output
)
clear_button.click(
fn=clear_form,
outputs=input_components
)
return demo
# Launch the app
if __name__ == "__main__":
demo = create_interface()
demo.launch()