mroccuper commited on
Commit
7e8ee64
·
verified ·
1 Parent(s): ba1e66b

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +242 -0
app.py ADDED
@@ -0,0 +1,242 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import google.generativeai as genai
3
+ import re
4
+ import json
5
+ from functools import lru_cache
6
+
7
+ # Global configuration
8
+ MAX_CACHE_SIZE = 100
9
+ CHAR_LIMITS = {
10
+ "title": 60,
11
+ "brand_min": 34,
12
+ "brand_max": 50,
13
+ "bullet": 256
14
+ }
15
+
16
+ def count_characters(text):
17
+ """Count characters in text."""
18
+ return len(text) if text else 0
19
+
20
+ def validate_listing(result, quote, niche, target, keywords):
21
+ """Validate all listing elements meet requirements"""
22
+ errors = []
23
+ keyword_list = [k.strip().lower() for k in keywords.split(",")]
24
+
25
+ # Title validation
26
+ title = result.get("title", "")
27
+ if len(title) != CHAR_LIMITS["title"]:
28
+ errors.append(f"Title length invalid: {len(title)} characters")
29
+ if not all(kw in title.lower() for kw in [quote.lower(), niche.lower(), target.lower()]):
30
+ errors.append("Title missing required elements")
31
+
32
+ # Brand validation
33
+ brand = result.get("brand_name", "")
34
+ if not (CHAR_LIMITS["brand_min"] <= len(brand) <= CHAR_LIMITS["brand_max"]):
35
+ errors.append(f"Brand name length invalid: {len(brand)} characters")
36
+
37
+ # Bullet points validation
38
+ for i, bp in enumerate([result.get("bullet_point_1", ""), result.get("bullet_point_2", "")]):
39
+ if len(bp) != CHAR_LIMITS["bullet"]:
40
+ errors.append(f"Bullet point {i+1} length invalid: {len(bp)} characters")
41
+ if not re.match(r'^[A-Z ]{5,20}[A-Z][a-z]', bp): # Check for ALL CAPS start
42
+ errors.append(f"Bullet point {i+1} doesn't start with ALL CAPS")
43
+ for keyword in keyword_list[:3]: # Check primary keywords
44
+ if keyword and keyword not in bp.lower():
45
+ errors.append(f"Bullet point {i+1} missing keyword: {keyword}")
46
+
47
+ return errors
48
+
49
+ def format_output(result, quote, niche, target, keywords):
50
+ """Format the output with character counts and validation"""
51
+ validation_errors = validate_listing(result, quote, niche, target, keywords)
52
+
53
+ output = f"Title ({count_characters(result.get('title', ''))}/{CHAR_LIMITS['title']} characters):\n{result.get('title', '')}\n"
54
+ output += f"Brand Name ({count_characters(result.get('brand_name', ''))}/{CHAR_LIMITS['brand_max']} characters):\n{result.get('brand_name', '')}\n"
55
+ output += f"Bullet Point 1 ({count_characters(result.get('bullet_point_1', ''))}/{CHAR_LIMITS['bullet']} characters):\n{result.get('bullet_point_1', '')}\n"
56
+ output += f"Bullet Point 2 ({count_characters(result.get('bullet_point_2', ''))}/{CHAR_LIMITS['bullet']} characters):\n{result.get('bullet_point_2', '')}"
57
+
58
+ if result.get("suggested_keywords"):
59
+ output += f"\nSuggested Additional Keywords:\n{result.get('suggested_keywords')}"
60
+
61
+ if validation_errors:
62
+ output += "\n\nVALIDATION ERRORS:\n" + "\n".join(validation_errors)
63
+
64
+ return output
65
+
66
+ def generate_prompt(quote, niche, target, keywords, product_type="T-Shirt"):
67
+ """Enhanced prompt with explicit SEO patterns"""
68
+ combined_prompt = f"""You are an Amazon Merch on Demand SEO expert specializing in creating optimized t-shirt and apparel listings.
69
+ MY INPUT IS ABOUT: A {niche} {product_type} with the design/quote: "{quote}" for {target}.
70
+ SEO BEST PRACTICES:
71
+ - Title structure: [Primary Keyword] [Design Reference] [Target Audience] [Secondary Keywords]
72
+ - Brand Name: Combine niche + target + emotional benefit (e.g., "TeacherJoy Designs")
73
+ - Bullet Point Structure:
74
+ • Start with ALL CAPS benefit statement
75
+ • Include 3-5 keywords
76
+ • Add emotional trigger + practical benefit
77
+
78
+ YOU MUST ONLY create an Amazon apparel listing about that EXACT input - no substitutions or different themes allowed.
79
+ Generate a listing that includes:
80
+ 1. Title (exactly {CHAR_LIMITS['title']} characters): Must include "{niche}" and reference the design/quote "{quote}" and target audience "{target}"
81
+ 2. Brand Name ({CHAR_LIMITS['brand_min']}-{CHAR_LIMITS['brand_max']} characters): Create a fitting brand name for this specific {niche} apparel for {target}
82
+ 3. Bullet Point 1 (exactly {CHAR_LIMITS['bullet']} characters): Highlight key features using ALL CAPS for the first 2-3 words
83
+ 4. Bullet Point 2 (exactly {CHAR_LIMITS['bullet']} characters): Highlight additional features using ALL CAPS for the first 2-3 words
84
+ The listing should be specifically for {product_type}s for the Amazon Merch on Demand program.
85
+ The listing MUST be about: {niche} + {quote} + for {target}. Do not generate content about other holidays, quotes, or audiences.
86
+ Use these specific keywords in your listing: {keywords}
87
+
88
+ MANDATORY SEO PATTERNS:
89
+ Title Examples:
90
+ - "[Holiday] [Quote] [Target] T-Shirt"
91
+ - "[Target] [Quote] [Holiday] Shirt"
92
+ - "[Quote] [Target] [Holiday] Tee"
93
+
94
+ Respond ONLY with a JSON object in this format:
95
+ {{
96
+ "title": "Title text here",
97
+ "brand_name": "Brand name here",
98
+ "bullet_point_1": "Bullet point 1 text here",
99
+ "bullet_point_2": "Bullet point 2 text here",
100
+ "suggested_keywords": "Comma separated list of 5 additional keywords"
101
+ }}
102
+ The output must follow these exact character counts..."""
103
+ return combined_prompt
104
+
105
+ @lru_cache(maxsize=MAX_CACHE_SIZE)
106
+ def cached_generate_listing(api_key, quote, niche, target, keywords, product_type):
107
+ """Cached version of the listing generation"""
108
+ try:
109
+ genai.configure(api_key=api_key)
110
+ model = genai.GenerativeModel('gemini-1.5-pro')
111
+
112
+ prompt = generate_prompt(quote, niche, target, keywords, product_type)
113
+
114
+ response = model.generate_content(
115
+ prompt,
116
+ generation_config={
117
+ "temperature": 0.3,
118
+ "top_p": 0.8,
119
+ "max_output_tokens": 2048
120
+ }
121
+ )
122
+
123
+ response_text = response.text
124
+ match = re.search(r'{.*}', response_text, re.DOTALL)
125
+ if match:
126
+ return json.loads(match.group(0))
127
+ return {"error": "Could not extract JSON from response"}
128
+ except Exception as e:
129
+ return {"error": str(e)}
130
+
131
+ def generate_amazon_listing(api_key, quote, niche, target, keywords, product_type):
132
+ """Main function to generate Amazon listing with validation"""
133
+ try:
134
+ # Generate main listing
135
+ result = cached_generate_listing(
136
+ api_key, quote, niche, target, keywords, product_type
137
+ )
138
+
139
+ # Generate variations
140
+ variations_prompt = generate_multiple_variations_prompt(quote, niche, target, keywords, product_type)
141
+ # Similar implementation for variations...
142
+
143
+ return format_output(result, quote, niche, target, keywords)
144
+ except Exception as e:
145
+ return f"Error: {str(e)}"
146
+
147
+ def create_interface():
148
+ """Create Gradio interface with enhanced UI"""
149
+ with gr.Blocks(title="Amazon Merch on Demand Listing Generator") as app:
150
+ gr.Markdown("# Amazon Merch on Demand Listing Generator")
151
+ gr.Markdown("Generate SEO-optimized t-shirt and apparel listings for Amazon Merch on Demand using Gemini 1.5 Pro AI.")
152
+
153
+ with gr.Row():
154
+ with gr.Column():
155
+ api_key = gr.Textbox(
156
+ label="Gemini API Key",
157
+ placeholder="Enter your Gemini API key",
158
+ type="password"
159
+ )
160
+
161
+ product_type = gr.Radio(
162
+ choices=["T-Shirt", "Hoodie", "Sweater", "Tank Top"],
163
+ label="Product Type",
164
+ value="T-Shirt"
165
+ )
166
+
167
+ quote = gr.Textbox(
168
+ label="Quote/Design/Idea",
169
+ placeholder="Enter the quote or design idea"
170
+ )
171
+ quote_count = gr.Textbox(
172
+ label="Character Count",
173
+ value="0",
174
+ interactive=False
175
+ )
176
+
177
+ niche = gr.Textbox(
178
+ label="Holiday/Event",
179
+ placeholder="Enter the holiday or event (e.g., St Patrick's Day)"
180
+ )
181
+ niche_count = gr.Textbox(
182
+ label="Character Count",
183
+ value="0",
184
+ interactive=False
185
+ )
186
+
187
+ target = gr.Textbox(
188
+ label="Target Audience",
189
+ placeholder="Teacher, Mom, Dad, etc."
190
+ )
191
+ target_count = gr.Textbox(
192
+ label="Character Count",
193
+ value="0",
194
+ interactive=False
195
+ )
196
+
197
+ keywords = gr.Textbox(
198
+ label="Target Keywords",
199
+ placeholder="Enter keywords separated by commas",
200
+ lines=5
201
+ )
202
+
203
+ submit_btn = gr.Button("Generate Amazon Listing", variant="primary")
204
+
205
+ with gr.Column():
206
+ output = gr.Textbox(
207
+ label="Generated Amazon Listing",
208
+ lines=25
209
+ )
210
+ validation_status = gr.Textbox(
211
+ label="Validation Status",
212
+ value="Pending",
213
+ interactive=False
214
+ )
215
+
216
+ # Event listeners for live character counting
217
+ quote.change(fn=lambda x: str(count_characters(x)), inputs=[quote], outputs=[quote_count])
218
+ niche.change(fn=lambda x: str(count_characters(x)), inputs=[niche], outputs=[niche_count])
219
+ target.change(fn=lambda x: str(count_characters(x)), inputs=[target], outputs=[target_count])
220
+
221
+ submit_btn.click(
222
+ fn=generate_amazon_listing,
223
+ inputs=[api_key, quote, niche, target, keywords, product_type],
224
+ outputs=[output, validation_status]
225
+ )
226
+
227
+ gr.Markdown("## Example Input")
228
+ gr.Markdown('''
229
+ Quote/Design: Rainbow with a quote "Lucky To Be A Teacher"
230
+ Holiday: St Patricks Day
231
+ Target: Teacher, Teacher Mom
232
+ 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
233
+ Product Type: T-Shirt
234
+ ''')
235
+
236
+ return app
237
+
238
+ # Create and launch the app
239
+ app = create_interface()
240
+
241
+ if __name__ == "__main__":
242
+ app.launch()