File size: 14,471 Bytes
7e8ee64
 
 
 
 
 
 
 
 
15ee1ac
 
 
 
 
 
7e8ee64
15ee1ac
 
7e8ee64
 
 
15ee1ac
 
7e8ee64
 
15ee1ac
7e8ee64
15ee1ac
7e8ee64
15ee1ac
 
 
 
 
 
 
1c4e7c2
 
15ee1ac
 
 
 
 
 
 
7e8ee64
 
15ee1ac
7e8ee64
 
 
438e750
 
 
 
 
7e8ee64
15ee1ac
1c4e7c2
15ee1ac
7e8ee64
 
15ee1ac
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
438e750
 
 
15ee1ac
 
438e750
 
 
15ee1ac
438e750
 
 
15ee1ac
 
 
 
 
438e750
 
 
 
 
 
7e8ee64
15ee1ac
7e8ee64
 
438e750
 
 
7e8ee64
438e750
7e8ee64
438e750
7e8ee64
 
 
438e750
 
 
 
 
 
 
 
 
 
 
 
 
15ee1ac
 
 
438e750
 
15ee1ac
438e750
 
 
 
 
 
 
 
 
 
 
5ec2ec2
 
438e750
5ec2ec2
 
438e750
 
 
813fec2
438e750
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15ee1ac
438e750
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15ee1ac
438e750
 
 
 
 
 
7e8ee64
 
 
15ee1ac
7e8ee64
 
 
 
 
 
 
15ee1ac
438e750
 
 
 
7e8ee64
 
 
438e750
15ee1ac
7e8ee64
438e750
 
 
 
 
 
 
 
 
 
 
 
 
7e8ee64
438e750
15ee1ac
438e750
 
7e8ee64
 
 
 
15ee1ac
7e8ee64
 
 
 
15ee1ac
 
 
438e750
 
 
 
 
 
 
7e8ee64
 
 
 
 
15ee1ac
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
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
import gradio as gr
import google.generativeai as genai
import re
import json

def count_characters(text):
    """Count characters in text."""
    return len(text) if text else 0

def format_output(title, brand_name, bullet1, bullet2, suggested_keywords=None):
    """Format the output with character counts."""
    output = f"Title ({count_characters(title)}/60 characters):\n{title}\n\n"
    output += f"Brand Name ({count_characters(brand_name)}/50 characters):\n{brand_name}\n\n"
    output += f"Bullet Point 1 ({count_characters(bullet1)}/256 characters):\n{bullet1}\n\n"
    output += f"Bullet Point 2 ({count_characters(bullet2)}/256 characters):\n{bullet2}"
    
    if suggested_keywords:
        output += f"\n\nSuggested Additional Keywords:\n{suggested_keywords}"
    
    return output

def generate_prompt(quote, niche, target, keywords):
    """Generate the prompt for Gemini API."""
    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} t-shirt with the design/quote: "{quote}" for {target}.
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 60 characters): Must include "{niche}" and reference the design/quote "{quote}" and target audience "{target}"
2. Brand Name (34-50 characters): Create a fitting brand name for this specific {niche} apparel for {target}
3. Bullet Point 1 (240-256 characters): Highlight key features using ALL CAPS for the first 2-3 words. Focus ONLY on the design, quote, and niche theme.
4. Bullet Point 2 (240-256 characters): Highlight additional features using ALL CAPS for the first 2-3 words. Focus ONLY on the design, quote, and niche theme.

IMPORTANT RULES FOR BULLET POINTS:
- Bullet point 1 must be between 240-256 characters
- Bullet point 2 must be between 240-256 characters
- DO NOT include generic phrases like "PREMIUM QUALITY" or references to material quality
- DO NOT include phrases like "This comfortable and stylish tee is made with high-quality materials for a soft feel and long-lasting wear"
- Focus ONLY on the specific design, niche, and quote provided
- Every sentence must directly relate to the quote, niche theme, and target audience
- Do not include any content that strays from the specific theme provided

The listing should be specifically for t-shirts, hoodies, or sweaters 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}

Respond ONLY with a JSON object in this format:
{{
  "title": "The title with exactly 60 characters",
  "brand_name": "Brand name between 34-50 characters",
  "bullet_point_1": "First bullet point between 240-256 characters that focuses on the design and theme",
  "bullet_point_2": "Second bullet point between 240-256 characters that focuses on the design and theme",
  "suggested_keywords": "5 additional keywords separated by commas"
}}

REMINDER: Make sure to count the characters carefully. Title should be EXACTLY 60 characters. Bullet point 1 must be between 240-256 characters and Bullet point 2 must be between 240-256 characters."""

    return combined_prompt

def generate_multiple_variations_prompt(quote, niche, target, keywords):
    """Generate the prompt for multiple variations of title and brand name."""
    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} t-shirt with the design/quote: "{quote}" for {target}.
YOU MUST ONLY create variations about that EXACT input - no substitutions or different themes allowed.

Generate 3 different variations for the Title and Brand Name based on the provided information.
All variations MUST be about {niche} + "{quote}" + for {target} audience.

The titles MUST include:
- The specific holiday/event: {niche}
- Reference to the quote/design: "{quote}"
- The target audience: {target}

Focus only on t-shirts, sweaters, and hoodies for the Amazon Merch on Demand program.
All titles must be exactly 60 characters and brand names between 34-50 characters.

Respond ONLY with a JSON object in this format:
{{
  "title_variations": [
    "Title variation 1 - exactly 60 characters, count carefully",
    "Title variation 2 - exactly 60 characters, count carefully",
    "Title variation 3 - exactly 60 characters, count carefully"
  ],
  "brand_name_variations": [
    "Brand name variation 1 (34-50 characters)",
    "Brand name variation 2 (34-50 characters)",
    "Brand name variation 3 (34-50 characters)"
  ]
}}

REMINDER: Make sure each title is EXACTLY 60 characters. Count carefully!"""

    return combined_prompt

def generate_amazon_listing(api_key, quote, niche, target, keywords):
    """Generate Amazon listing using Gemini API."""
    # Input validation
    if not api_key:
        return "Error: Please enter a valid Gemini API key"
    if not quote or not niche or not target:
        return "Error: Please fill in all required fields (Quote, Holiday/Event, and Target Audience)"
    
    try:
        # Configure the Gemini API with the provided key
        genai.configure(api_key=api_key)
        
        # Create model with optimized settings
        model = genai.GenerativeModel(
            'gemini-1.5-pro',
            generation_config={
                "temperature": 0.3,
                "top_p": 0.8,
                "max_output_tokens": 1024,  # Reduced for faster response
            }
        )
        
        # Generate the main listing
        prompt = generate_prompt(quote, niche, target, keywords)
        
        try:
            # First try to get just the main listing for faster response
            response = model.generate_content(prompt)
            
            # Extract JSON from the response
            response_text = response.text
            match = re.search(r'{.*}', response_text, re.DOTALL)
            if not match:
                return "Error: Could not extract JSON from Gemini API response. Please try again."
                
            json_str = match.group(0)
            try:
                result = json.loads(json_str)
            except json.JSONDecodeError:
                return "Error parsing JSON response from Gemini API. Please try again."
                
            # Validate that the output actually matches the input criteria
            title = result.get("title", "")
            if not (quote.lower() in title.lower() or 
                   niche.lower() in title.lower() or 
                   any(t.lower() in title.lower() for t in target.lower().split(','))):
                return f"Error: Generated title doesn't match the requested theme: '{quote}', '{niche}', or '{target}'. Please try again."
            
            # Validate bullet point lengths
            bullet1 = result.get("bullet_point_1", "")
            bullet2 = result.get("bullet_point_2", "")
            
            #if len(bullet1) < 240 or len(bullet1) > 256:
                #return f"Error: Bullet point 1 length ({len(bullet1)}) is not between 240-256 characters. Please try again."
            
            #if len(bullet2) < 240 or len(bullet2) > 256:
                #return f"Error: Bullet point 2 length ({len(bullet2)}) is not between 240-256 characters. Please try again."
            
            # Check for generic content in bullet points
            generic_phrases = ["premium quality", "high-quality materials", "soft feel", "long-lasting wear", 
                              "comfortable and stylish"]
            
            for phrase in generic_phrases:
                if phrase in bullet1.lower() or phrase in bullet2.lower():
                    return f"Error: Generated bullet points contain generic phrase '{phrase}'. Please try again."
            
            # Format main output first - so we have something to show quickly
            main_output = format_output(
                result.get("title", "Error generating title"),
                result.get("brand_name", "Error generating brand name"),
                result.get("bullet_point_1", "Error generating bullet point 1"),
                result.get("bullet_point_2", "Error generating bullet point 2"),
                result.get("suggested_keywords", "Error generating suggested keywords")
            )
            
            # Now try to get variations in a separate call
            try:
                variations_prompt = generate_multiple_variations_prompt(quote, niche, target, keywords)
                response_var = model.generate_content(
                    variations_prompt,
                    generation_config={
                        "temperature": 0.4,
                        "top_p": 0.8,
                        "max_output_tokens": 1024
                    }
                )
                
                # Extract JSON from the variations response
                response_var_text = response_var.text
                match_var = re.search(r'{.*}', response_var_text, re.DOTALL)
                if match_var:
                    json_str_var = match_var.group(0)
                    try:
                        variations = json.loads(json_str_var)
                        
                        # Format variations output
                        variations_output = "\n\nADDITIONAL VARIATIONS:\n\n"
                        variations_output += "Title Variations:\n"
                        for i, var in enumerate(variations.get("title_variations", []), 1):
                            variations_output += f"{i}. {var} ({count_characters(var)}/60 characters)\n"
                        
                        variations_output += "\nBrand Name Variations:\n"
                        for i, var in enumerate(variations.get("brand_name_variations", []), 1):
                            variations_output += f"{i}. {var} ({count_characters(var)}/50 characters)\n"
                        
                        # Combine main output with variations
                        return main_output + variations_output
                        
                    except json.JSONDecodeError:
                        # Return just the main output if we can't parse variations
                        return main_output + "\n\n(Could not generate variations)"
                else:
                    # Return just the main output if we can't extract JSON for variations
                    return main_output + "\n\n(Could not generate variations)"
                    
            except Exception as var_error:
                # Return just the main output if variations fail
                return main_output + f"\n\n(Could not generate variations: {str(var_error)})"
                
        except genai.types.generation_types.BlockedPromptException as e:
            return f"Error: The prompt was blocked by Gemini API safety filters. Please modify your input and try again."
            
        except Exception as e:
            return f"Error generating main listing: {str(e)}"
            
    except Exception as e:
        return f"Error: {str(e)}"

# Create the Gradio interface
def create_interface():
    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")
                quote = gr.Textbox(label="Quote/Design/Idea", placeholder="Enter the quote or design idea", value="")
                niche = gr.Textbox(label="Holiday/Event", placeholder="Enter the holiday or event (e.g., St Patrick's Day)", value="")
                target = gr.Textbox(label="Target Audience", placeholder="Teacher, Mom, Dad, etc.", value="")
                keywords = gr.Textbox(label="Target Keywords", placeholder="Enter keywords separated by commas", lines=5, value="")
                submit_btn = gr.Button("Generate Amazon Listing", variant="primary")
            
            with gr.Column():
                status = gr.Textbox(label="Status", value="Ready to generate listing", interactive=False)
                output = gr.Textbox(label="Generated Amazon Listing", lines=25)
        
        def on_submit(api_key, quote, niche, target, keywords):
            # Update status first
            yield "Generating listing... Please wait.", output.value
            
            # Generate the listing
            result = generate_amazon_listing(api_key, quote, niche, target, keywords)
            
            # Update status with completion message
            if "Error" in result:
                yield "Error occurred. See details below.", result
            else:
                yield "Listing generated successfully!", result
        
        submit_btn.click(
            fn=on_submit,
            inputs=[api_key, quote, niche, target, keywords],
            outputs=[status, output],
            show_progress="minimal"
        )
        
        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
```
        ''')
        
        gr.Markdown("""
        ## Troubleshooting Tips
        - If you experience timeouts, try using shorter, more specific inputs
        - Make sure your Gemini API key is valid and has sufficient quota
        - The app will prioritize showing the main listing first, then try to generate variations
        """)
        
    return app

# Create and launch the app
app = create_interface()

# For deployment on Hugging Face Spaces
if __name__ == "__main__":
    app.launch()