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()