import gradio as gr import google.generativeai as genai import os import json import re import time import random # CSS for styling the app css = """ body { font-family: 'Poppins', -apple-system, BlinkMacSystemFont, sans-serif; #background-color: #fafafa; } .container { max-width: 900px; margin: auto; } .title { text-align: center; margin-bottom: 0.5em; color: #333; font-weight: 800; } .subtitle { text-align: center; margin-bottom: 2em; color: #555; font-style: italic; } .output-box { padding: 20px; margin-top: 15px; font-family: 'Courier New', monospace; white-space: pre-wrap; } footer { text-align: center; margin-top: 2em; padding: 15px; font-size: 0.8em; color: #888; border-top: 1px solid #eee; } .api-key-container { padding: 20px; margin-bottom: 25px; } .prompt-container { margin-bottom: 20px; border-left: 4px solid #e94560; padding-left: 15px; } .gr-button-primary { background-color: #e94560 !important; border: none !important; } .gr-button-primary:hover { background-color: #d63d56 !important; } .copy-btn { margin-top: 10px; text-align: right; } .examples-container { margin-top: 15px; padding: 10px; border-radius: 8px; background-color: #f0f0f0; } .tab-content { padding: 20px; background-color: #fff; } .logo { text-align: center; margin: 20px auto; } .logo img { max-width: 80px; height: auto; } .tabs-container { margin-top: 20px; } .style-options { margin-top: 15px; } .market-box { margin-top: 15px; padding: 15px; border: 1px solid #ddd; border-radius: 8px; background-color: #f9f9f9; } .keyword-list { margin-top: 5px; font-family: 'Courier New', monospace; } """ # MODIFIED FUNCTION: Generate structured POD marketing content def generate_pod_structured_output(api_key, quote, num_design_prompts, ui_selected_style_name="None (Let AI decide)"): genai.configure(api_key=api_key) model = genai.GenerativeModel( model_name="gemini-1.5-pro", generation_config={ "temperature": 0.85, # Slightly higher for more variety in more prompts "top_p": 0.95, "top_k": 40, "max_output_tokens": 3072, # Increased slightly for potentially more prompts } ) style_for_header_tag = "AUTO" style_guidance_for_llm = "AI chooses the best-fitting style automatically" if ui_selected_style_name and ui_selected_style_name != "None (Let AI decide)": style_for_header_tag = ui_selected_style_name style_guidance_for_llm = f"The user has selected a preferred style: '{ui_selected_style_name}'. You MUST apply this style to all relevant prompts in Section 4." else: style_guidance_for_llm = "The user has left the style choice empty. AI should choose the best-fitting style automatically for Section 4." # The 'num_design_prompts' now dictates the number of ideas in Section 4 system_prompt = f"""You are a smart Print-on-Demand (POD) marketing assistant. Your task is to analyze the quote "{quote}" and return FOUR structured sections that help with marketing, audience targeting, and design execution. The system has an OPTIONAL STYLES section. {style_guidance_for_llm} --- Return only the following four sections: šŸ“ˆ 1. AMAZON SEARCH KEYWORDS Generate a comma-separated list of 15-25 SEO-rich keywords relevant to the quote "{quote}". - Mix of broad and niche-specific terms - Focus on what real buyers would search for on Amazon Example: dog lover shirt, funny pet shirt, dog humor tee, running with dog --- šŸ“… 2. HOLIDAYS / EVENTS / NICHES Identify all relevant holidays, occasions, events, and niche categories the quote "{quote}" fits into. (Provide at least 3-5 items) - Be specific and include both evergreen and seasonal contexts Example: Dog Lovers, Pet Adoption Month, National Dog Day, Funny Workout Shirts --- šŸŽÆ 3. TARGET AUDIENCE Describe the ideal customer this quote/design ("{quote}") would appeal to. - Include: age range, gender, interests, lifestyle traits, tone preference Example: Adults 25–45, pet lovers, dog moms, people with sarcastic or playful humor, casual wearers --- šŸŽØ 4. PROMPTS ({num_design_prompts} Ideas) — STYLE: [{style_for_header_tag}] Generate exactly {num_design_prompts} creative design prompts for the quote: "{quote}", based on: - Tone and meaning of the quote - The style determined above (either user-selected '{style_for_header_tag if style_for_header_tag != "AUTO" else "AI Choice"}' or AI-recommended if AUTO) - Each prompt should include layout, typography style, design elements, and color ideas. If a style was provided by the user, apply it consistently. If no style was provided (AUTO), analyze the quote and recommend and apply a fitting visual style. Example (If User Selected Style = Silhouette and num_design_prompts = 1): "1. Bold, stacked text in athletic font for THE PROVIDED QUOTE. A silhouette of a dog pulling a leash with a person chasing behind. High contrast black-and-white design optimized for light shirts." Example (If Style = AUTO, AI chose Retro, and num_design_prompts = 1): "1. Retro block lettering in faded orange and teal for THE PROVIDED QUOTE. Text arches above a cartoon dog flexing with sunglasses. Distressed texture for a vintage look." --- āš ļø Output Format Guidelines: - Use headers exactly as shown (including the emojis, numbering, and the dynamic prompt count in Section 4 header). - For Section 4, number each design prompt idea starting from 1. - Do NOT restate the provided quote "{quote}" unless it's within the design prompt itself where it's part of the design concept. - Do NOT explain your reasoning outside the requested sections. - Keep your output clean and implementation-ready, directly providing the content under each header. - Ensure each section is clearly delineated by the headers and newlines. """ print("--- SYSTEM PROMPT BEING SENT TO API (First 500 chars) ---") print(system_prompt[:500] + "...") print("--- END OF SYSTEM PROMPT PREVIEW ---") try: print(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] Attempting to generate {num_design_prompts} prompts for quote: '{quote}' with style: '{ui_selected_style_name}'") response = model.generate_content([system_prompt]) print(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] Received response from API.") return response.text, None except Exception as e: error_message = f"Error during API call: {str(e)}" print(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] {error_message}") if hasattr(e, 'message'): error_message = f"API Error: {e.message}" return None, error_message # MODIFIED PARSING FUNCTION for the structured output def parse_structured_output(text_output): data = { "keywords_header": "šŸ“ˆ 1. AMAZON SEARCH KEYWORDS", "keywords_content": "Not found or parsing error.", "holidays_header": "šŸ“… 2. HOLIDAYS / EVENTS / NICHES", "holidays_content": "Not found or parsing error.", "audience_header": "šŸŽÆ 3. TARGET AUDIENCE", "audience_content": "Not found or parsing error.", "prompts_header": "šŸŽØ 4. PROMPTS — STYLE: N/A", # Default, will be replaced "prompts_content": "Not found or parsing error." } kw_match = re.search(r"(šŸ“ˆ 1\. AMAZON SEARCH KEYWORDS)\s*\n(.*?)(?=\n\nšŸ“… 2\. HOLIDAYS / EVENTS / NICHES|\Z)", text_output, re.DOTALL) if kw_match: data["keywords_header"] = kw_match.group(1).strip() data["keywords_content"] = kw_match.group(2).strip() hol_match = re.search(r"(šŸ“… 2\. HOLIDAYS / EVENTS / NICHES)\s*\n(.*?)(?=\n\nšŸŽÆ 3\. TARGET AUDIENCE|\Z)", text_output, re.DOTALL) if hol_match: data["holidays_header"] = hol_match.group(1).strip() data["holidays_content"] = hol_match.group(2).strip() # Lookahead for prompts section needs to be dynamic or very general aud_match = re.search(r"(šŸŽÆ 3\. TARGET AUDIENCE)\s*\n(.*?)(?=\n\nšŸŽØ 4\. PROMPTS \(\d+ Ideas?\) — STYLE:|\Z)", text_output, re.DOTALL) if aud_match: data["audience_header"] = aud_match.group(1).strip() data["audience_content"] = aud_match.group(2).strip() # Regex for prompts header is now more general to capture the number of ideas # It matches "šŸŽØ 4. PROMPTS (N Ideas) — STYLE: [STYLE]" prompt_header_pattern_match = re.search(r"(šŸŽØ 4\. PROMPTS \(\d+\s*Ideas?\) — STYLE:.*?)\s*\n(.*?)\Z", text_output, re.DOTALL) if prompt_header_pattern_match: data["prompts_header"] = prompt_header_pattern_match.group(1).strip() data["prompts_content"] = prompt_header_pattern_match.group(2).strip() else: # Fallback if the "(N Ideas)" part is missing for some reason prompt_fallback_match = re.search(r"(šŸŽØ 4\. PROMPTS — STYLE:.*?)\s*\n(.*?)\Z", text_output, re.DOTALL) if prompt_fallback_match: data["prompts_header"] = prompt_fallback_match.group(1).strip() data["prompts_content"] = prompt_fallback_match.group(2).strip() print("Warning: Parsed prompts using fallback regex. Header might not exactly match '(N Ideas)'.") return data # Function to analyze quote sentiment and suggest styles def analyze_quote(api_key, quote, progress=gr.Progress()): if not api_key: return "Please enter your Gemini API key for analysis." if not quote: return "Please enter a quote to analyze." genai.configure(api_key=api_key) model = genai.GenerativeModel( model_name="gemini-1.5-pro", generation_config={"temperature": 0.7, "top_p": 0.95, "max_output_tokens": 1000} ) system_prompt = f"""Analyze the following quote: "{quote}" Provide a brief analysis of: 1. The overall mood and sentiment of the quote 2. The most appropriate typography styles for this quote 3. Suggested color palettes that would complement the meaning 4. Best type of decorative elements to include Format your response as a concise paragraph for each point.""" try: response = model.generate_content([system_prompt]) return response.text except Exception as e: return f"Error analyzing quote: {str(e)}" # MODIFIED Function to handle form submission def process_quote(api_key, quote, num_prompts_from_slider, ui_style_preference_str, progress=gr.Progress()): if not api_key: return "Please enter your Gemini API key.", "API key is required." if not quote: return "Please enter a quote.", "A quote is required." # Ensure num_prompts_from_slider is an int for the system prompt try: num_design_prompts = int(num_prompts_from_slider) except ValueError: return "Invalid number of prompts selected.", "Error with prompt count." progress(0, desc="Initializing...") time.sleep(0.1) progress(0.2, desc=f"Generating {num_design_prompts} design prompts & marketing content...") # Pass num_design_prompts to the generation function raw_llm_output, error = generate_pod_structured_output(api_key, quote, num_design_prompts, ui_style_preference_str) if error: return f"Error from API: {error}", f"Marketing insights could not be retrieved. Details: {error}" if not raw_llm_output: return "Received no content from API.", "Received no content for marketing insights from API." progress(0.7, desc="Parsing API output...") parsed_data = parse_structured_output(raw_llm_output) market_info_text = ( f"{parsed_data['keywords_header']}\n{parsed_data['keywords_content']}\n\n" f"{parsed_data['holidays_header']}\n{parsed_data['holidays_content']}\n\n" f"{parsed_data['audience_header']}\n{parsed_data['audience_content']}" ) prompts_text = f"{parsed_data['prompts_header']}\n{parsed_data['prompts_content']}" if "Not found or parsing error." in prompts_text and "Not found or parsing error." in market_info_text: error_message = "Could not fully parse the API output. This might indicate an unexpected response format from the AI." raw_output_preview = raw_llm_output[:1000] + "..." if len(raw_llm_output) > 1000 else raw_llm_output prompts_text = error_message + "\n\nRaw API Output (preview):\n" + raw_output_preview market_info_text = "See main output area for details on parsing failure." progress(1.0, desc="Done!") return prompts_text, market_info_text example_quotes = [ "good vibes only", "dream big, sparkle more", "best mom ever", "adventure awaits", "but first, coffee", "fueled by caffeine and chaos", "stay wild moon child" ] def create_demo(): with gr.Blocks(css=css, theme=gr.themes.Soft()) as demo: gr.Markdown("""

✨ POD Marketing & Prompt Generator ✨

Generate Amazon keywords, target audiences, niches, and design prompts for your quotes using Gemini 1.5 Pro
""") with gr.Tabs() as tabs: with gr.TabItem("Generate Content"): with gr.Group(elem_classes="api-key-container"): api_key_input = gr.Textbox(label="Gemini API Key", placeholder="Enter your Gemini API key here...", type="password", info="Your API key is not stored and only used for this session") quote_input = gr.Textbox(label="Your Quote/Text", placeholder="Enter the quote you want to analyze...", info="Example: \"good vibes only\"", lines=2) with gr.Group(elem_classes="style-options"): gr.Markdown("### Style Preferences for Design Prompts (Section 4)") with gr.Row(): # num_prompts_slider now directly controls the number of design ideas num_prompts_slider = gr.Slider( minimum=5, maximum=15, value=7, step=1, # Default to 7 label="Number of Design Ideas for Section 4", info="Select how many design prompts to generate for Section 4." ) style_preference_radio = gr.Radio( ["None (Let AI decide)", "Retro 70s", "Modern Minimal", "Hand-drawn", "Feminine/Girly", "Bold Experimental", "Silhouette", "Cartoon", "Vintage"], label="Preferred Style for Design Prompts", value="None (Let AI decide)", info="Optional: Choose a preferred style for Section 4 design prompts." ) submit_btn = gr.Button("Generate Marketing Content & Prompts", variant="primary", size="lg") gr.Examples(examples=example_quotes, inputs=quote_input, label="Example Quotes") prompts_output_textbox = gr.Textbox(label="šŸŽØ Design Prompts (Section 4)", placeholder="Creative design prompts will appear here...", lines=15, elem_classes=["output-box"], show_copy_button=True) marketing_insights_textbox = gr.Textbox(label="šŸ“ˆšŸ“…šŸŽÆ Marketing Insights (Sections 1-3)", placeholder="Amazon Keywords, Holidays/Niches, and Target Audience will appear here...", lines=15, elem_classes=["output-box", "market-box"], show_copy_button=True) with gr.TabItem("Quote Analysis (Alternative)"): with gr.Group(elem_classes="api-key-container"): analysis_api_key = gr.Textbox(label="Gemini API Key", placeholder="Enter your Gemini API key here...", type="password", info="Your API key is not stored.") analysis_quote_input = gr.Textbox(label="Your Quote/Text", placeholder="Enter a quote to analyze its mood, style, colors...", lines=2) analyze_btn = gr.Button("Analyze Quote", variant="primary") analysis_output_textbox = gr.Textbox(label="Quote Analysis Details", placeholder="Detailed analysis of mood, style, colors, elements will appear here...", lines=10, elem_classes=["output-box"]) with gr.TabItem("Help"): gr.Markdown(""" ### How to Use the POD Marketing & Prompt Generator 1. **Get a Gemini API Key**: Visit [Google AI Studio](https://makersuite.google.com/) and generate an API key. 2. **Enter Your API Key**: In the "Generate Content" or "Quote Analysis" tab. 3. **Enter Your Quote**: The text you want to base your T-shirt design and marketing on. 4. **Number of Design Ideas**: Use the slider to choose how many design prompts (5-15) you want for Section 4. 5. **Choose Style (Optional)**: Select a preferred visual style for the design prompts in Section 4. If "None" is selected, the AI will choose. 6. **Generate Content**: Click "Generate Marketing Content & Prompts". ### Output Sections (Generate Content Tab): * **šŸ“ˆ 1. AMAZON SEARCH KEYWORDS** * **šŸ“… 2. HOLIDAYS / EVENTS / NICHES** * **šŸŽÆ 3. TARGET AUDIENCE** * **šŸŽØ 4. PROMPTS ([Number Selected] Ideas) — STYLE: [AUTO or SELECTED STYLE]** Sections 1, 2, and 3 appear in "Marketing Insights". Section 4 appears in "Design Prompts". ### Quote Analysis Tab Offers analysis on: mood, general typography styles, color palettes, decorative elements. """) submit_btn.click( fn=process_quote_with_style_mapping, inputs=[api_key_input, quote_input, num_prompts_slider, style_preference_radio], outputs=[prompts_output_textbox, marketing_insights_textbox] ) analyze_btn.click(fn=analyze_quote, inputs=[analysis_api_key, analysis_quote_input], outputs=analysis_output_textbox) gr.HTML(""" """, visible=False) gr.Markdown("") return demo def process_quote_with_style_mapping(api_key, quote, num_prompts, ui_style_preference_str, progress=gr.Progress()): return process_quote(api_key, quote, num_prompts, ui_style_preference_str, progress) if __name__ == "__main__": demo = create_demo() demo.launch()