AMZ-Listing-Pro / app.py
mroccuper's picture
Create app.py
7e8ee64 verified
raw
history blame
10.5 kB
import gradio as gr
import google.generativeai as genai
import re
import json
from functools import lru_cache
# Global configuration
MAX_CACHE_SIZE = 100
CHAR_LIMITS = {
"title": 60,
"brand_min": 34,
"brand_max": 50,
"bullet": 256
}
def count_characters(text):
"""Count characters in text."""
return len(text) if text else 0
def validate_listing(result, quote, niche, target, keywords):
"""Validate all listing elements meet requirements"""
errors = []
keyword_list = [k.strip().lower() for k in keywords.split(",")]
# Title validation
title = result.get("title", "")
if len(title) != CHAR_LIMITS["title"]:
errors.append(f"Title length invalid: {len(title)} characters")
if not all(kw in title.lower() for kw in [quote.lower(), niche.lower(), target.lower()]):
errors.append("Title missing required elements")
# Brand validation
brand = result.get("brand_name", "")
if not (CHAR_LIMITS["brand_min"] <= len(brand) <= CHAR_LIMITS["brand_max"]):
errors.append(f"Brand name length invalid: {len(brand)} characters")
# Bullet points validation
for i, bp in enumerate([result.get("bullet_point_1", ""), result.get("bullet_point_2", "")]):
if len(bp) != CHAR_LIMITS["bullet"]:
errors.append(f"Bullet point {i+1} length invalid: {len(bp)} characters")
if not re.match(r'^[A-Z ]{5,20}[A-Z][a-z]', bp): # Check for ALL CAPS start
errors.append(f"Bullet point {i+1} doesn't start with ALL CAPS")
for keyword in keyword_list[:3]: # Check primary keywords
if keyword and keyword not in bp.lower():
errors.append(f"Bullet point {i+1} missing keyword: {keyword}")
return errors
def format_output(result, quote, niche, target, keywords):
"""Format the output with character counts and validation"""
validation_errors = validate_listing(result, quote, niche, target, keywords)
output = f"Title ({count_characters(result.get('title', ''))}/{CHAR_LIMITS['title']} characters):\n{result.get('title', '')}\n"
output += f"Brand Name ({count_characters(result.get('brand_name', ''))}/{CHAR_LIMITS['brand_max']} characters):\n{result.get('brand_name', '')}\n"
output += f"Bullet Point 1 ({count_characters(result.get('bullet_point_1', ''))}/{CHAR_LIMITS['bullet']} characters):\n{result.get('bullet_point_1', '')}\n"
output += f"Bullet Point 2 ({count_characters(result.get('bullet_point_2', ''))}/{CHAR_LIMITS['bullet']} characters):\n{result.get('bullet_point_2', '')}"
if result.get("suggested_keywords"):
output += f"\nSuggested Additional Keywords:\n{result.get('suggested_keywords')}"
if validation_errors:
output += "\n\nVALIDATION ERRORS:\n" + "\n".join(validation_errors)
return output
def generate_prompt(quote, niche, target, keywords, product_type="T-Shirt"):
"""Enhanced prompt with explicit SEO patterns"""
combined_prompt = f"""You are an Amazon Merch on Demand SEO expert specializing in creating optimized t-shirt and apparel listings.
MY INPUT IS ABOUT: A {niche} {product_type} with the design/quote: "{quote}" for {target}.
SEO BEST PRACTICES:
- Title structure: [Primary Keyword] [Design Reference] [Target Audience] [Secondary Keywords]
- Brand Name: Combine niche + target + emotional benefit (e.g., "TeacherJoy Designs")
- Bullet Point Structure:
• Start with ALL CAPS benefit statement
• Include 3-5 keywords
• Add emotional trigger + practical benefit
YOU MUST ONLY create an Amazon apparel listing about that EXACT input - no substitutions or different themes allowed.
Generate a listing that includes:
1. Title (exactly {CHAR_LIMITS['title']} characters): Must include "{niche}" and reference the design/quote "{quote}" and target audience "{target}"
2. Brand Name ({CHAR_LIMITS['brand_min']}-{CHAR_LIMITS['brand_max']} characters): Create a fitting brand name for this specific {niche} apparel for {target}
3. Bullet Point 1 (exactly {CHAR_LIMITS['bullet']} characters): Highlight key features using ALL CAPS for the first 2-3 words
4. Bullet Point 2 (exactly {CHAR_LIMITS['bullet']} characters): Highlight additional features using ALL CAPS for the first 2-3 words
The listing should be specifically for {product_type}s for the Amazon Merch on Demand program.
The listing MUST be about: {niche} + {quote} + for {target}. Do not generate content about other holidays, quotes, or audiences.
Use these specific keywords in your listing: {keywords}
MANDATORY SEO PATTERNS:
Title Examples:
- "[Holiday] [Quote] [Target] T-Shirt"
- "[Target] [Quote] [Holiday] Shirt"
- "[Quote] [Target] [Holiday] Tee"
Respond ONLY with a JSON object in this format:
{{
"title": "Title text here",
"brand_name": "Brand name here",
"bullet_point_1": "Bullet point 1 text here",
"bullet_point_2": "Bullet point 2 text here",
"suggested_keywords": "Comma separated list of 5 additional keywords"
}}
The output must follow these exact character counts..."""
return combined_prompt
@lru_cache(maxsize=MAX_CACHE_SIZE)
def cached_generate_listing(api_key, quote, niche, target, keywords, product_type):
"""Cached version of the listing generation"""
try:
genai.configure(api_key=api_key)
model = genai.GenerativeModel('gemini-1.5-pro')
prompt = generate_prompt(quote, niche, target, keywords, product_type)
response = model.generate_content(
prompt,
generation_config={
"temperature": 0.3,
"top_p": 0.8,
"max_output_tokens": 2048
}
)
response_text = response.text
match = re.search(r'{.*}', response_text, re.DOTALL)
if match:
return json.loads(match.group(0))
return {"error": "Could not extract JSON from response"}
except Exception as e:
return {"error": str(e)}
def generate_amazon_listing(api_key, quote, niche, target, keywords, product_type):
"""Main function to generate Amazon listing with validation"""
try:
# Generate main listing
result = cached_generate_listing(
api_key, quote, niche, target, keywords, product_type
)
# Generate variations
variations_prompt = generate_multiple_variations_prompt(quote, niche, target, keywords, product_type)
# Similar implementation for variations...
return format_output(result, quote, niche, target, keywords)
except Exception as e:
return f"Error: {str(e)}"
def create_interface():
"""Create Gradio interface with enhanced UI"""
with gr.Blocks(title="Amazon Merch on Demand Listing Generator") as app:
gr.Markdown("# Amazon Merch on Demand Listing Generator")
gr.Markdown("Generate SEO-optimized t-shirt and apparel listings for Amazon Merch on Demand using Gemini 1.5 Pro AI.")
with gr.Row():
with gr.Column():
api_key = gr.Textbox(
label="Gemini API Key",
placeholder="Enter your Gemini API key",
type="password"
)
product_type = gr.Radio(
choices=["T-Shirt", "Hoodie", "Sweater", "Tank Top"],
label="Product Type",
value="T-Shirt"
)
quote = gr.Textbox(
label="Quote/Design/Idea",
placeholder="Enter the quote or design idea"
)
quote_count = gr.Textbox(
label="Character Count",
value="0",
interactive=False
)
niche = gr.Textbox(
label="Holiday/Event",
placeholder="Enter the holiday or event (e.g., St Patrick's Day)"
)
niche_count = gr.Textbox(
label="Character Count",
value="0",
interactive=False
)
target = gr.Textbox(
label="Target Audience",
placeholder="Teacher, Mom, Dad, etc."
)
target_count = gr.Textbox(
label="Character Count",
value="0",
interactive=False
)
keywords = gr.Textbox(
label="Target Keywords",
placeholder="Enter keywords separated by commas",
lines=5
)
submit_btn = gr.Button("Generate Amazon Listing", variant="primary")
with gr.Column():
output = gr.Textbox(
label="Generated Amazon Listing",
lines=25
)
validation_status = gr.Textbox(
label="Validation Status",
value="Pending",
interactive=False
)
# Event listeners for live character counting
quote.change(fn=lambda x: str(count_characters(x)), inputs=[quote], outputs=[quote_count])
niche.change(fn=lambda x: str(count_characters(x)), inputs=[niche], outputs=[niche_count])
target.change(fn=lambda x: str(count_characters(x)), inputs=[target], outputs=[target_count])
submit_btn.click(
fn=generate_amazon_listing,
inputs=[api_key, quote, niche, target, keywords, product_type],
outputs=[output, validation_status]
)
gr.Markdown("## Example Input")
gr.Markdown('''
Quote/Design: Rainbow with a quote "Lucky To Be A Teacher"
Holiday: St Patricks Day
Target: Teacher, Teacher Mom
Keywords: lucky, teacher, rainbow, st, patricks, day, t-shirt, patrick's, outfit, design, leopard, cheetah, print, shamrock, clover, perfect, men, women, teachers, celebrate, saint, patrick, special, unique, makes, great, gifts, idea, substitute, love, irish, culture, pattys, holiday, teach, shamrocks, cute, design, awesome, show, students
Product Type: T-Shirt
''')
return app
# Create and launch the app
app = create_interface()
if __name__ == "__main__":
app.launch()