Spaces:
Running
Running
File size: 10,485 Bytes
7e8ee64 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
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() |