Spaces:
Running
Running
import gradio as gr | |
import openai | |
import os | |
from dotenv import load_dotenv | |
import logging | |
import datetime | |
import json | |
import re | |
import random | |
# Set up logging with more detailed configuration | |
log_dir = "logs" | |
if not os.path.exists(log_dir): | |
os.makedirs(log_dir) | |
log_filename = os.path.join(log_dir, f"svg_generator_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}.log") | |
logging.basicConfig( | |
filename=log_filename, | |
level=logging.INFO, | |
format='%(asctime)s - %(levelname)s - [%(filename)s:%(lineno)d] - %(message)s' | |
) | |
# Add console handler to see logs in terminal | |
console_handler = logging.StreamHandler() | |
console_handler.setLevel(logging.INFO) | |
console_formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') | |
console_handler.setFormatter(console_formatter) | |
logging.getLogger().addHandler(console_handler) | |
# Load environment variables | |
load_dotenv() | |
logging.info("Environment variables loaded") | |
# Configure OpenAI API | |
api_key = os.getenv("OPENAI_API_KEY") | |
if not api_key: | |
logging.error("OPENAI_API_KEY not found in environment variables!") | |
raise ValueError("OPENAI_API_KEY not found!") | |
client = openai.OpenAI(api_key=api_key) | |
logging.info("OpenAI client initialized successfully") | |
def clean_svg_content(content): | |
"""Clean and validate SVG content""" | |
# Remove any leading/trailing whitespace | |
content = content.strip() | |
# Log original content for debugging | |
logging.info(f"Original content starts with: {content[:100]}...") | |
# Remove XML declaration if present | |
content = re.sub(r'<\?xml[^>]+\?>\s*', '', content) | |
# Remove DOCTYPE if present | |
content = re.sub(r'<!DOCTYPE[^>]+>\s*', '', content) | |
# Remove any comments | |
content = re.sub(r'<!--[\s\S]*?-->\s*', '', content) | |
# Remove any empty lines | |
content = '\n'.join(line for line in content.splitlines() if line.strip()) | |
# Log cleaned content | |
logging.info(f"Cleaned content starts with: {content[:100]}...") | |
return content | |
def validate_svg(content): | |
"""Validate SVG content""" | |
# Check if content starts with <svg tag (allowing for attributes) | |
if not re.match(r'\s*<svg[\s>]', content): | |
logging.warning(f"Content doesn't start with SVG tag. Content starts with: {content[:100]}") | |
return False | |
# Check if content has matching closing tag | |
if not content.strip().endswith('</svg>'): | |
logging.warning("Content doesn't end with closing SVG tag") | |
return False | |
return True | |
def generate_svg(prompt): | |
"""Generate SVG using the fine-tuned GPT-4 model""" | |
try: | |
logging.info(f"Sending request to OpenAI API with prompt: {prompt[:100]}...") | |
logging.info(f"Using model: ft:gpt-4o-mini-2024-07-18:personal::AyNMN2ax") | |
response = client.chat.completions.create( | |
model="ft:gpt-4o-mini-2024-07-18:personal::AyNMN2ax", | |
messages=[ | |
{"role": "system", "content": """in this add this Create a well-aligned and meaningful SVG generator prompt. Ensure it includes appropriate alignment and content instructions. | |
# Output Format | |
The SVG should be generated with structured alignment and include meaningful attributes such as colors, dimensions, and positioning. | |
# Steps [optional] | |
1. Define the shapes and their attributes (e.g., circles, rectangles). | |
2. Set the colors and dimensions. | |
3. Align the objects to create a cohesive design. | |
4. Review and adjust for meaningfulness and symmetry. | |
# Examples [optional] | |
Example Input: | |
- Shapes: Circle, Rectangle | |
- Colors: Blue, Red | |
- Sizes: 100x100, 50x50 | |
- Positioning: Center | |
Example Output: | |
```svg | |
<svg width="200" height="200"> | |
<circle cx="100" cy="100" r="50" fill="blue" /> | |
<rect x="75" y="75" width="50" height="50" fill="red"/> | |
</svg> | |
``` | |
# Notes [optional] | |
- Ensure the SVG is valid and adheres to SVG standards. | |
- Ensure in output only generate the svg only in svg you can create comment it's okay | |
- Consider accessibility aspects such as color contrast. | |
- Review the design for visual balance and clarity. | |
- IMPORTANT: Return ONLY the raw SVG code without any markdown formatting or explanations. The response should start with <svg and end with </svg>."""}, | |
{"role": "user", "content": prompt} | |
], | |
temperature=1, # Reduced for more consistent output | |
max_tokens=2000, | |
) | |
# Log the response details | |
logging.info(f"Response received from OpenAI API") | |
logging.info(f"Response finish reason: {response.choices[0].finish_reason}") | |
# Get and clean the SVG content | |
svg_content = response.choices[0].message.content | |
logging.info(f"Raw SVG length: {len(svg_content)} characters") | |
# Clean the SVG content | |
cleaned_svg = clean_svg_content(svg_content) | |
logging.info(f"Cleaned SVG length: {len(cleaned_svg)} characters") | |
# Validate the cleaned SVG | |
if not validate_svg(cleaned_svg): | |
error_msg = "Invalid SVG format received from API" | |
logging.error(error_msg) | |
return f"""<svg width="400" height="100" xmlns="http://www.w3.org/2000/svg"> | |
<rect width="100%" height="100%" fill="#ffebee"/> | |
<text x="10" y="40" fill="red" font-family="Arial">Error: {error_msg}</text> | |
<text x="10" y="80" fill="#666" font-family="Arial" font-size="12"> | |
Please try again with a different prompt | |
</text> | |
</svg>""" | |
return cleaned_svg | |
except openai.APIError as e: | |
error_msg = f"OpenAI API Error: {str(e)}" | |
logging.error(error_msg) | |
return f"""<svg width="400" height="100" xmlns="http://www.w3.org/2000/svg"> | |
<rect width="100%" height="100%" fill="#ffebee"/> | |
<text x="10" y="40" fill="red" font-family="Arial">{error_msg}</text> | |
</svg>""" | |
except openai.APIConnectionError as e: | |
error_msg = f"Connection Error: {str(e)}" | |
logging.error(error_msg) | |
return f"""<svg width="400" height="100" xmlns="http://www.w3.org/2000/svg"> | |
<rect width="100%" height="100%" fill="#ffebee"/> | |
<text x="10" y="40" fill="red" font-family="Arial">{error_msg}</text> | |
</svg>""" | |
except openai.RateLimitError as e: | |
error_msg = f"Rate Limit Error: {str(e)}" | |
logging.error(error_msg) | |
return f"""<svg width="400" height="100" xmlns="http://www.w3.org/2000/svg"> | |
<rect width="100%" height="100%" fill="#ffebee"/> | |
<text x="10" y="40" fill="red" font-family="Arial">{error_msg}</text> | |
</svg>""" | |
except Exception as e: | |
error_msg = f"Unexpected Error: {str(e)}" | |
logging.error(error_msg, exc_info=True) | |
return f"""<svg width="400" height="100" xmlns="http://www.w3.org/2000/svg"> | |
<rect width="100%" height="100%" fill="#ffebee"/> | |
<text x="10" y="40" fill="red" font-family="Arial">{error_msg}</text> | |
</svg>""" | |
def create_preview_svg(svg_content): | |
"""Create a preview version of the SVG with proper sizing""" | |
# Force width and height to 1080 for full size preview | |
svg_content = re.sub(r'width="[^"]+"', 'width="1080"', svg_content) | |
svg_content = re.sub(r'height="[^"]+"', 'height="1080"', svg_content) | |
# Ensure viewBox is present | |
if 'viewBox' not in svg_content: | |
svg_content = svg_content.replace('<svg', '<svg viewBox="0 0 1080 1080"', 1) | |
return svg_content | |
def create_fullview_html(svg): | |
"""Create HTML for full-view modal with proper sizing""" | |
return f""" | |
<div style="width:1080px; height:1080px; overflow:auto; background-color:#f0f0f0; padding:20px;"> | |
{svg} | |
</div> | |
""" | |
def generate_similar_prompts(example_prompt): | |
"""Generate 10 similar testimonial prompts based on an example prompt using GPT-4 mini""" | |
system_prompt = """You are a creative testimonial prompt generator. Based on the following example prompt, | |
generate 10 unique testimonial prompts that start with 'Create' and are similar in style but with variations in:""" | |
user_prompt = f"Example prompt: {example_prompt}\n\nGenerate 10 similar prompts that start with 'Create', with good alignment and default positioning" | |
try: | |
logging.info("Sending request to OpenAI API for similar prompts...") | |
response = client.chat.completions.create( | |
model="gpt-4o-mini-2024-07-18", | |
messages=[ | |
{"role": "system", "content": system_prompt}, | |
{"role": "user", "content": user_prompt} | |
], | |
temperature=0.7, | |
max_tokens=500 | |
) | |
prompts_text = response.choices[0].message.content.strip() | |
logging.info("Received similar prompts from OpenAI API") | |
prompts_list = [line.strip() for line in prompts_text.splitlines() if line.strip()] | |
# Ensure each prompt includes quality requirements and SVG code request | |
quality_prompts = [] | |
for prompt in prompts_list: | |
if "good alignment" not in prompt.lower() and "default positioning" not in prompt.lower(): | |
prompt += " create svg code with good alignment, default word positioning and high SVG quality. Please provide complete SVG code." | |
quality_prompts.append(prompt) | |
if len(quality_prompts) < 10: | |
extra_count = 10 - len(quality_prompts) | |
unique_prompts = [f"{example_prompt} - variation {i+1} with good alignment, default word positioning and high SVG quality. Please provide complete SVG code." for i in range(extra_count)] | |
quality_prompts += unique_prompts | |
else: | |
quality_prompts = quality_prompts[:10] | |
# Add default SVG code request to all prompts | |
final_prompts = [] | |
for prompt in quality_prompts: | |
if "create svg code" not in prompt.lower(): | |
prompt += " Please create complete SVG code with proper structure and elements." | |
final_prompts.append(prompt) | |
return final_prompts | |
except Exception as e: | |
error_msg = f"Error generating similar prompts: {str(e)}" | |
logging.error(error_msg, exc_info=True) | |
return [f"{example_prompt} - variation {i+1} with good alignment, default word positioning and high SVG quality. Please provide complete SVG code." for i in range(10)] | |
def generate_random_prompt(user_prompt=None): | |
""" | |
Generate a unique prompt based on user's input prompt. | |
If no prompt is provided, use a default example. | |
Ensures all generated prompts maintain quality standards. | |
""" | |
if not user_prompt: | |
user_prompt = "Design a modern testimonial with a clean layout, balanced typography, and vibrant color accents." | |
# Add quality requirements to the base prompt | |
base_prompt = f"{user_prompt} The design must have good alignment, balanced composition, and professional SVG quality." | |
# Generate variations based on the enhanced base prompt | |
prompts = generate_similar_prompts(base_prompt) | |
# Ensure each prompt includes quality requirements | |
quality_prompts = [] | |
for prompt in prompts: | |
if "good alignment" not in prompt.lower() and "svg quality" not in prompt.lower(): | |
prompt += " Ensure good alignment and high SVG quality." | |
quality_prompts.append(prompt) | |
return random.choice(quality_prompts) | |
def process_all_prompts(*prompts): | |
"""Process all prompts and return SVG results with preview and full-view versions""" | |
preview_results = [] | |
fullview_results = [] | |
logging.info(f"Starting to process {len(prompts)} prompts") | |
for i, prompt in enumerate(prompts, 1): | |
logging.info(f"\n{'='*50}") | |
logging.info(f"Processing prompt {i} of {len(prompts)}") | |
try: | |
if prompt.strip(): | |
modified_prompt = prompt.strip() + " The design must have good alignment and be visually appealing." | |
logging.info(f"Prompt {i} content: {modified_prompt[:100]}...") | |
svg = generate_svg(modified_prompt) | |
preview_svg = create_preview_svg(svg) | |
logging.info(f"Successfully generated SVG for prompt {i}") | |
logging.info(f"SVG size: {len(svg)} characters") | |
preview_results.append(preview_svg) | |
fullview_results.append(svg) | |
else: | |
default_svg = """<svg width="300" height="300" xmlns="http://www.w3.org/2000/svg"> | |
<rect width="100%" height="100%" fill="#f5f5f5"/> | |
<text x="50%" y="50%" fill="#666" font-family="Arial" text-anchor="middle"> | |
No prompt provided | |
</text> | |
</svg>""" | |
logging.info(f"Empty prompt {i} received - using default SVG") | |
preview_results.append(default_svg) | |
fullview_results.append(default_svg) | |
except Exception as e: | |
error_msg = f"Error processing prompt {i}: {str(e)}" | |
logging.error(error_msg, exc_info=True) | |
error_svg = f"""<svg width="300" height="300" xmlns="http://www.w3.org/2000/svg"> | |
<rect width="100%" height="100%" fill="#ffebee"/> | |
<text x="50%" y="40%" fill="red" font-family="Arial" text-anchor="middle"> | |
Error generating SVG | |
</text> | |
<text x="50%" y="60%" fill="#666" font-family="Arial" font-size="12" text-anchor="middle"> | |
{error_msg} | |
</text> | |
</svg>""" | |
preview_results.append(error_svg) | |
fullview_results.append(error_svg) | |
logging.info(f"Completed processing prompt {i}") | |
logging.info(f"{'='*50}\n") | |
logging.info(f"Completed processing all {len(prompts)} prompts") | |
return tuple(preview_results) + (fullview_results,) | |
def generate_svg_wrapper(prompt): | |
""" | |
Wrapper function to handle SVG generation and create preview | |
Returns the preview SVG, full SVG, and a status message for display | |
""" | |
if not prompt: | |
return None, None, "β Please enter a prompt first!" | |
modified_prompt = prompt.strip() + " The design must have good alignment and be visually appealing." | |
svg = generate_svg(modified_prompt) | |
preview_svg = create_preview_svg(svg) | |
return preview_svg, svg, "β Generated SVG for prompt!" | |
def generate_svg_and_show_code_fn(prompt): | |
"""Wrapper function to generate an SVG and immediately show the SVG code below the preview.""" | |
preview, code, status = generate_svg_wrapper(prompt) | |
return preview, gr.update(value=code, visible=True), status | |
def generate_multiple_svgs(*args): | |
# Use the values from prompt boxes instead of generating new ones | |
prompts = [arg for arg in args if arg and isinstance(arg, str)] | |
num_galleries = len(svg_galleries) | |
num_code_boxes = len(code_boxes) | |
if not prompts: | |
empty_preview = '<div style="width:1080px; height:1080px; display:flex; justify-content:center; align-items:center; background:#f5f5f5;">Generate prompts first</div>' | |
outputs = [] | |
# Add status and container updates | |
outputs.append("β Please generate and edit prompts first before generating designs!") # status message | |
outputs.append(gr.update(visible=False)) # multi_svg_container | |
outputs.append(gr.update(visible=True)) # single_svg_container | |
# Add gallery outputs with visibility updates | |
for _ in range(num_galleries): | |
outputs.append(gr.update(value=empty_preview, visible=False)) | |
# Add code outputs with visibility updates | |
for _ in range(num_code_boxes): | |
outputs.append(gr.update(value="", visible=False)) | |
return outputs | |
try: | |
logging.info(f"Generating SVGs for {len(prompts)} prompts") | |
gallery_outputs = [] | |
code_outputs = [] | |
for prompt in prompts: | |
if prompt.strip(): | |
preview_svg, full_svg, _ = generate_svg_wrapper(prompt) | |
gallery_outputs.append(gr.update(value=preview_svg, visible=True)) | |
code_outputs.append(gr.update(value=full_svg, visible=False)) | |
else: | |
gallery_outputs.append(gr.update(value='<div style="width:1080px; height:1080px; display:flex; justify-content:center; align-items:center; background:#f5f5f5;">No prompt provided</div>', visible=True)) | |
code_outputs.append(gr.update(value="", visible=False)) | |
outputs = [] | |
# Add status and container updates | |
outputs.append("β Generated designs based on your edited prompts!") # status message | |
outputs.append(gr.update(visible=True)) # multi_svg_container | |
outputs.append(gr.update(visible=False)) # single_svg_container | |
# Add gallery outputs | |
for i in range(num_galleries): | |
if i < len(gallery_outputs): | |
outputs.append(gallery_outputs[i]) | |
else: | |
outputs.append(gr.update(value='<div style="width:1080px; height:1080px; display:flex; justify-content:center; align-items:center; background:#f5f5f5;">No design</div>', visible=False)) | |
# Add code outputs | |
for i in range(num_code_boxes): | |
if i < len(code_outputs): | |
outputs.append(code_outputs[i]) | |
else: | |
outputs.append(gr.update(value="", visible=False)) | |
logging.info("Successfully generated all SVGs") | |
return outputs | |
except Exception as e: | |
error_msg = f"Error generating SVGs: {str(e)}" | |
logging.error(error_msg, exc_info=True) | |
error_preview = '<div style="width:1080px; height:1080px; display:flex; justify-content:center; align-items:center; background:#ffebee;">Error generating SVG</div>' | |
outputs = [] | |
# Add status and container updates | |
outputs.append(f"β {error_msg}") # status message | |
outputs.append(gr.update(visible=False)) # multi_svg_container | |
outputs.append(gr.update(visible=True)) # single_svg_container | |
# Add gallery outputs with visibility updates | |
for _ in range(num_galleries): | |
outputs.append(gr.update(value=error_preview, visible=False)) | |
# Add code outputs with visibility updates | |
for _ in range(num_code_boxes): | |
outputs.append(gr.update(value="", visible=False)) | |
return outputs | |
# Create the Gradio interface | |
with gr.Blocks(theme=gr.themes.Soft()) as app: | |
gr.Markdown("# SVG Generator with Similar Prompt Generation") | |
gr.Markdown("### Step 1: Enter an example prompt to generate similar prompts") | |
example_prompt_input = gr.Textbox(label="Example Prompt", placeholder="Enter an example testimonial prompt here...", lines=3) | |
generate_examples_btn = gr.Button("Generate 10 Similar Prompts") | |
gr.Markdown("### Step 2: Review and edit the generated prompts") | |
prompts = [gr.Textbox(label=f"Prompt {i+1}", placeholder=f"Generated prompt {i+1}...") for i in range(10)] | |
# When button is clicked, populate the 10 prompt textboxes | |
generate_examples_btn.click(fn=generate_similar_prompts, inputs=example_prompt_input, outputs=prompts) | |
gr.Markdown("### Step 3: Generate SVGs for the above prompts") | |
generate_btn = gr.Button("Generate SVGs", variant="primary", size="lg") | |
# Store full-view SVGs | |
fullview_svgs = gr.State([]) | |
preview_outputs = [] | |
# Create grid layout for SVG previews | |
with gr.Row(): | |
with gr.Column(scale=1): | |
for i in range(0, 5): # First column | |
with gr.Group(): | |
preview = gr.HTML(label=f"SVG {i+1}", container=True) | |
preview_outputs.append(preview) | |
# Add a button that opens the full view in a new tab | |
def create_view_fn(index): | |
def view_fn(svgs): | |
if svgs and len(svgs) > index: | |
return f""" | |
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Full Size SVG {index + 1}</title> | |
<style> | |
body {{ | |
margin: 0; | |
padding: 20px; | |
display: flex; | |
justify-content: center; | |
align-items: flex-start; | |
min-height: 100vh; | |
background-color: #f0f0f0; | |
gap: 20px; | |
}} | |
.svg-container {{ | |
width: 1080px; | |
height: 1080px; | |
background-color: white; | |
padding: 20px; | |
border-radius: 10px; | |
box-shadow: 0 0 20px rgba(0,0,0,0.1); | |
}} | |
.code-container {{ | |
width: 600px; | |
background-color: white; | |
padding: 20px; | |
border-radius: 10px; | |
box-shadow: 0 0 20px rgba(0,0,0,0.1); | |
}} | |
pre {{ | |
white-space: pre-wrap; | |
word-wrap: break-word; | |
background-color: #f5f5f5; | |
padding: 15px; | |
border-radius: 5px; | |
margin: 0; | |
font-family: monospace; | |
font-size: 14px; | |
line-height: 1.4; | |
max-height: 1080px; | |
overflow-y: auto; | |
}} | |
.copy-button {{ | |
margin-top: 10px; | |
padding: 8px 16px; | |
background-color: #4CAF50; | |
color: white; | |
border: none; | |
border-radius: 4px; | |
cursor: pointer; | |
font-size: 14px; | |
}} | |
.copy-button:hover {{ | |
background-color: #45a049; | |
}} | |
</style> | |
</head> | |
<body> | |
<div class="svg-container"> | |
{svgs[index]} | |
</div> | |
<div class="code-container"> | |
<h3>SVG Code</h3> | |
<pre id="svg-code">{svgs[index].replace('<', '<').replace('>', '>')}</pre> | |
<button class="copy-button" onclick="copyCode()">Copy SVG Code</button> | |
</div> | |
<script> | |
function copyCode() {{ | |
const code = document.getElementById('svg-code').textContent; | |
navigator.clipboard.writeText(code).then(() => {{ | |
const btn = document.querySelector('.copy-button'); | |
btn.textContent = 'Copied!'; | |
setTimeout(() => btn.textContent = 'Copy SVG Code', 2000); | |
}}); | |
}} | |
</script> | |
</body> | |
</html> | |
""" | |
return "" | |
return view_fn | |
with gr.Row(): | |
view_btn = gr.Button(f"View Full Size {i+1}", size="sm") | |
full_view = gr.HTML(visible=False) | |
view_btn.click( | |
fn=create_view_fn(i), | |
inputs=[fullview_svgs], | |
outputs=[full_view], | |
js=""" | |
async function(svg_html) { | |
if (svg_html) { | |
const win = window.open("", "_blank"); | |
win.document.write(svg_html); | |
} | |
return ""; | |
} | |
""" | |
) | |
with gr.Column(scale=1): | |
for i in range(5, 10): # Second column | |
with gr.Group(): | |
preview = gr.HTML(label=f"SVG {i+1}", container=True) | |
preview_outputs.append(preview) | |
with gr.Row(): | |
view_btn = gr.Button(f"View Full Size {i+1}", size="sm") | |
full_view = gr.HTML(visible=False) | |
view_btn.click( | |
fn=create_view_fn(i), | |
inputs=[fullview_svgs], | |
outputs=[full_view], | |
js=""" | |
async function(svg_html) { | |
if (svg_html) { | |
const win = window.open("", "_blank"); | |
win.document.write(svg_html); | |
} | |
return ""; | |
} | |
""" | |
) | |
# Add some CSS to style the previews | |
gr.HTML(""" | |
<style> | |
.svg-preview { | |
border: 1px solid #ddd; | |
border-radius: 8px; | |
padding: 10px; | |
margin: 10px auto; | |
background: white; | |
width: 1080px !important; | |
height: 1080px !important; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
} | |
.preview-container { | |
display: flex; | |
flex-direction: column; | |
gap: 10px; | |
margin: 10px auto; | |
width: 1080px; | |
} | |
.gradio-html { | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
} | |
.gradio-html > div { | |
width: 1080px !important; | |
height: 1080px !important; | |
} | |
.gradio-html svg { | |
width: 1080px !important; | |
height: 1080px !important; | |
} | |
</style> | |
""") | |
generate_btn.click( | |
fn=process_all_prompts, | |
inputs=prompts, | |
outputs=preview_outputs + [fullview_svgs] | |
) | |
# Launch the app | |
if __name__ == "__main__": | |
logging.info("Starting SVG Generator application") | |
try: | |
with gr.Blocks(theme=gr.themes.Soft()) as demo: | |
gr.Markdown(""" | |
# π¨ SVG Testimonial Generator | |
### How to use: | |
1. Enter your own prompt OR generate a random prompt | |
2. Review the prompt and generate designs | |
3. View, download, or check the code for each design | |
""") | |
# Define containers and lists first | |
multi_svg_container = gr.Row(visible=False) | |
single_svg_container = gr.Row() | |
svg_galleries = [] | |
code_boxes = [] | |
code_visibilities = [] # Initialize code_visibilities list | |
# Create galleries, code boxes, and visibility states | |
for i in range(10): | |
svg_galleries.append(gr.HTML( | |
label=f"Preview {i+1}", | |
value='<div style="width:1080px; height:1080px; display:flex; justify-content:center; align-items:center; background:#f5f5f5; margin:0 auto;"><div style="width:1080px; height:1080px;">Waiting for generation...</div></div>', | |
visible=False | |
)) | |
code_box = gr.Textbox( | |
label=f"SVG Code {i+1}", | |
lines=5, | |
visible=False, | |
show_copy_button=True | |
) | |
code_boxes.append(code_box) | |
code_visibilities.append(gr.update(visible=False)) # Add visibility state for each code box | |
with gr.Row(): | |
with gr.Column(scale=3): | |
prompt_input = gr.Textbox( | |
label="βοΈ Enter Your Design Prompt", | |
lines=2, | |
placeholder="Example: Design a modern testimonial with a dark background, white text, and customer quote from John Doe about excellent service." | |
) | |
with gr.Row(): | |
with gr.Column(scale=1): | |
random_prompt_btn = gr.Button("π² Generate Random Prompt", variant="secondary", size="lg") | |
with gr.Column(scale=1): | |
generate_designs_btn = gr.Button("π¨ Generate 10 Designs", variant="primary", size="lg") | |
with gr.Column(scale=1): | |
generate_single_btn = gr.Button("π Generate Single SVG", variant="primary", size="lg") | |
# Status message for user feedback | |
status_message = gr.Markdown("") | |
# Container for editable prompts | |
with gr.Row() as prompts_container: | |
with gr.Column(): | |
prompt_boxes = [] | |
svg_previews = [] | |
generate_buttons = [] # Store generate buttons | |
for i in range(10): | |
with gr.Row(): | |
prompt_boxes.append(gr.Textbox( | |
label=f"βοΈ Prompt {i+1}", | |
lines=2, | |
interactive=True, | |
visible=False | |
)) | |
gen_btn = gr.Button(f"π¨ Generate SVG {i+1}", visible=False) | |
generate_buttons.append(gen_btn) # Store button reference | |
svg_preview = gr.HTML(visible=False) | |
svg_previews.append(svg_preview) | |
def create_generate_fn(index): | |
def generate_fn(prompt): | |
if not prompt: | |
return gr.update(visible=False), "β Please enter a prompt first!" | |
try: | |
svg_content = generate_svg(prompt) | |
preview_svg = create_preview_svg(svg_content) | |
return gr.update(value=preview_svg, visible=True), f"β Generated SVG for prompt {index + 1}!" | |
except Exception as e: | |
return gr.update(visible=False), f"β Error generating SVG: {str(e)}" | |
return generate_fn | |
gen_btn.click( | |
fn=create_generate_fn(i), | |
inputs=[prompt_boxes[i]], | |
outputs=[svg_previews[i], status_message] | |
) | |
# Add Generate All button | |
with gr.Row(): | |
generate_all_btn = gr.Button("π¨ Generate All SVGs", variant="primary", size="lg", visible=False) | |
def generate_and_show_prompts(current_prompt): | |
prompts = generate_similar_prompts(current_prompt) if current_prompt else [generate_random_prompt() for _ in range(10)] | |
outputs = [] | |
# Add prompt box updates | |
for prompt in prompts: | |
outputs.append(gr.update(value=prompt, visible=True)) | |
# Add status message | |
outputs.append("β Generated prompts! Click individual Generate buttons or Generate All to create designs!") | |
# Add generate all button visibility | |
outputs.append(gr.update(visible=True)) | |
# Add generate button visibilities | |
for _ in range(len(generate_buttons)): | |
outputs.append(gr.update(visible=True)) | |
return outputs | |
# Event handler for random prompt generation | |
random_prompt_btn.click( | |
fn=generate_and_show_prompts, | |
inputs=[prompt_input], | |
outputs=prompt_boxes + [status_message, generate_all_btn] + generate_buttons | |
) | |
# Event handler for Generate All button | |
generate_all_btn.click( | |
fn=generate_multiple_svgs, | |
inputs=prompt_boxes, | |
outputs=[status_message, multi_svg_container, single_svg_container] + svg_galleries + code_boxes | |
) | |
# Event handler for Generate Designs button | |
generate_designs_btn.click( | |
fn=generate_multiple_svgs, | |
inputs=prompt_boxes, | |
outputs=[status_message, multi_svg_container, single_svg_container] + svg_galleries + code_boxes | |
) | |
# Single SVG preview container | |
with gr.Row() as single_svg_container: | |
with gr.Column(min_width=1100): | |
svg_preview = gr.HTML( | |
label="Preview", | |
value='<div style="width:1080px; height:1080px; display:flex; justify-content:center; align-items:center; background:#f5f5f5; margin:0 auto;"><div style="width:1080px; height:1080px;">Enter prompt and click Generate</div></div>' | |
) | |
svg_code_box = gr.Textbox( | |
label="SVG Code", | |
lines=10, | |
visible=False, | |
show_copy_button=True | |
) | |
download_btn = gr.Button("πΎ Download", variant="secondary") | |
file_output = gr.File(label="Download", visible=False) | |
# Now, register the single SVG generation click event AFTER svg_code_box is defined: | |
generate_single_btn.click( | |
fn=generate_svg_and_show_code_fn, | |
inputs=[prompt_input], | |
outputs=[svg_preview, svg_code_box, status_message] | |
) | |
# Container for random prompts display (can be removed since we now use textboxes) | |
with gr.Row(visible=False) as random_prompts_container: | |
random_prompts_box = gr.Dataframe( | |
headers=["#", "Random Prompts"], | |
label="Generated Random Prompts", | |
interactive=False | |
) | |
# Container for multiple SVGs | |
with gr.Row(visible=False) as multi_svg_container: | |
with gr.Column(min_width=1100): | |
svg_galleries = [] | |
code_boxes = [] | |
code_visibilities = [] | |
view_code_buttons = [] | |
download_buttons = [] # Initialize download_buttons list | |
for i in range(10): | |
with gr.Group(): | |
gr.Markdown(f"### Design {i+1}") | |
# Preview container with fixed size | |
with gr.Column(min_width=1080): | |
# Preview | |
svg_galleries.append(gr.HTML( | |
label=f"Preview {i+1}", | |
value='<div style="width:1080px; height:1080px; display:flex; justify-content:center; align-items:center; background:#f5f5f5; margin:0 auto;"><div style="width:1080px; height:1080px;">Waiting for generation...</div></div>' | |
)) | |
with gr.Row(): | |
# View Code button | |
view_code_btn = gr.Button(f"π View Code {i+1}", variant="secondary") | |
view_code_buttons.append(view_code_btn) | |
# Download button | |
download_btn = gr.Button(f"πΎ Download {i+1}", variant="secondary") | |
# Code view | |
code_box = gr.Textbox( | |
label=f"SVG Code {i+1}", | |
lines=5, | |
visible=False, | |
show_copy_button=True | |
) | |
code_boxes.append(code_box) | |
code_visibilities.append(gr.update(visible=False)) | |
# Hidden file output | |
file_output = gr.File(label=f"Download {i+1}", visible=False) | |
download_buttons.append((download_btn, file_output)) | |
# Add separator | |
gr.Markdown("---") | |
def toggle_code_visibility(evt: gr.SelectData): | |
"""Toggle visibility of code box when view code button is clicked""" | |
index = evt.index | |
return gr.update(visible=True) if index < len(code_boxes) else gr.update(visible=False) | |
# Add click handlers for each view code button | |
for i, (view_btn, code_box) in enumerate(zip(view_code_buttons, code_boxes)): | |
view_btn.click( | |
fn=lambda: gr.update(visible=True), | |
inputs=None, | |
outputs=[code_box] | |
) | |
def download_svg(svg_code, index): | |
"""Download SVG file""" | |
if not svg_code: | |
return None | |
temp_file = f"testimonial_{index+1}.svg" | |
with open(temp_file, "w", encoding="utf-8") as f: | |
f.write(svg_code) | |
return temp_file | |
# Add click handlers for download buttons | |
for i, (download_btn, file_output) in enumerate(download_buttons): | |
download_btn.click( | |
fn=lambda x, idx=i: download_svg(x, idx), | |
inputs=[code_boxes[i]], | |
outputs=[file_output] | |
) | |
# Add click handler for single SVG download | |
download_btn.click( | |
fn=lambda x: download_svg(x, 0), | |
inputs=[svg_code_box], | |
outputs=[file_output] | |
) | |
demo.launch( | |
server_port=7860, # Default Gradio port | |
share=True, # Creates a shareable link | |
show_error=True | |
) | |
logging.info("Application launched successfully") | |
except Exception as e: | |
logging.error(f"Error launching application: {str(e)}", exc_info=True) |