varun324242 commited on
Commit
8c6fb72
Β·
verified Β·
1 Parent(s): fb0bcc4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +865 -332
app.py CHANGED
@@ -1,360 +1,893 @@
 
 
1
  import os
2
- import random
3
  import logging
4
- import math
5
- import base64
6
- import requests
7
- import gradio as gr
8
- from datetime import datetime
9
- from groq import Groq
10
- import svgwrite
11
- from IPython.display import display, HTML
 
12
 
13
- # Set up logging
14
  logging.basicConfig(
 
15
  level=logging.INFO,
16
- format='%(asctime)s - %(levelname)s - %(message)s',
17
- handlers=[
18
- logging.FileHandler(f'testimonial_generator_{datetime.now().strftime("%Y%m%d_%H%M%S")}.log'),
19
- logging.StreamHandler()
20
- ]
21
  )
22
- logger = logging.getLogger(__name__)
23
-
24
- logger.info("Initializing application")
25
-
26
- # Initialize Groq client
27
- # Replace with your actual Groq API key
28
- client = Groq(api_key="your_groq_api_key_here")
29
-
30
- # Create directories
31
- SAVE_DIRS = {
32
- 'images': 'testimonial_output/images',
33
- 'logs': 'testimonial_output/logs',
34
- 'fonts': 'testimonial_output/fonts',
35
- }
36
- for dir_path in SAVE_DIRS.values():
37
- os.makedirs(dir_path, exist_ok=True)
38
-
39
- class SVGShapeGenerator:
40
- @staticmethod
41
- def draw_circles(dwg, width, height, color, opacity=0.5):
42
- """Draw decorative circles in SVG"""
43
- fill_color = svgwrite.rgb(int(color[1:3], 16), int(color[3:5], 16), int(color[5:7], 16), '%')
44
- # Top left circles
45
- radius_range = range(10, 81, 20)
46
- for r in radius_range:
47
- dwg.add(dwg.circle(center=(20 + r, 20 + r), r=r, fill=fill_color, fill_opacity=opacity))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
 
49
- # Bottom right circles
50
- for r in radius_range:
51
- dwg.add(dwg.circle(center=(width - 20 - r, height - 20 - r), r=r, fill=fill_color, fill_opacity=opacity))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
53
- # Additional decorative circles
54
- dwg.add(dwg.circle(center=(width / 4 + 30, 80), r=30, fill=fill_color, fill_opacity=opacity))
55
- dwg.add(dwg.circle(center=(3 * width / 4 - 30, height - 80), r=30, fill=fill_color, fill_opacity=opacity))
56
-
57
- @staticmethod
58
- def draw_dots(dwg, width, height, color, opacity=0.5):
59
- """Draw dot patterns in SVG"""
60
- fill_color = svgwrite.rgb(int(color[1:3], 16), int(color[3:5], 16), int(color[5:7], 16), '%')
61
- sizes = [3, 5, 7]
62
- spacings = [40, 60, 80]
63
 
64
- for size, spacing in zip(sizes, spacings):
65
- for x in range(0, width, spacing):
66
- for y in range(0, height, spacing):
67
- if random.random() > 0.3: # 70% chance to draw a dot
68
- dwg.add(dwg.circle(center=(x + size / 2, y + size / 2), r=size / 2, fill=fill_color, fill_opacity=opacity))
69
-
70
- @staticmethod
71
- def draw_waves(dwg, width, height, color, opacity=0.5):
72
- """Draw wave patterns in SVG"""
73
- stroke_color = svgwrite.rgb(int(color[1:3], 16), int(color[3:5], 16), int(color[5:7], 16))
74
- amplitudes = [20, 30, 40]
75
- frequencies = [0.02, 0.01, 0.015]
76
- thicknesses = [2, 3, 4]
77
 
78
- for amp, freq, thick in zip(amplitudes, frequencies, thicknesses):
79
- for offset in range(0, height, 200):
80
- points = []
81
- for x in range(0, width, 2):
82
- y = offset + amp * math.sin(freq * x)
83
- points.append((x, y))
84
-
85
- if len(points) > 1:
86
- dwg.add(dwg.polyline(points=points, stroke=stroke_color, stroke_width=thick, fill="none", stroke_opacity=opacity))
87
-
88
- @staticmethod
89
- def draw_corners(dwg, width, height, color, opacity=0.5):
90
- """Draw corner decorations in SVG"""
91
- stroke_color = svgwrite.rgb(int(color[1:3], 16), int(color[3:5], 16), int(color[5:7], 16))
92
- size = 150
93
- thicknesses = [3, 5, 7]
94
 
95
- for t in thicknesses:
96
- # Top left
97
- dwg.add(dwg.line(start=(0, size), end=(0, 0), stroke=stroke_color, stroke_width=t, stroke_opacity=opacity))
98
- dwg.add(dwg.line(start=(0, 0), end=(size, 0), stroke=stroke_color, stroke_width=t, stroke_opacity=opacity))
99
-
100
- # Top right
101
- dwg.add(dwg.line(start=(width - size, 0), end=(width, 0), stroke=stroke_color, stroke_width=t, stroke_opacity=opacity))
102
- dwg.add(dwg.line(start=(width, 0), end=(width, size), stroke=stroke_color, stroke_width=t, stroke_opacity=opacity))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
 
104
- # Bottom left
105
- dwg.add(dwg.line(start=(0, height - size), end=(0, height), stroke=stroke_color, stroke_width=t, stroke_opacity=opacity))
106
- dwg.add(dwg.line(start=(0, height), end=(size, height), stroke=stroke_color, stroke_width=t, stroke_opacity=opacity))
 
 
 
107
 
108
- # Bottom right
109
- dwg.add(dwg.line(start=(width - size, height), end=(width, height), stroke=stroke_color, stroke_width=t, stroke_opacity=opacity))
110
- dwg.add(dwg.line(start=(width, height), end=(width, height - size), stroke=stroke_color, stroke_width=t, stroke_opacity=opacity))
111
-
112
- class TestimonialGenerator:
113
- def __init__(self, font_url='https://github.com/google/fonts/raw/main/ofl/poppins/Poppins-Medium.ttf'):
114
- logger.info("Initializing TestimonialGenerator")
115
- self.client = client
116
-
117
- # Background color combinations (background, text color, accent color)
118
- self.color_schemes = [
119
- ("#FFFFFF", "#000000", "#FF4081"), # White, Black, Pink
120
- ("#F5F5F5", "#333333", "#2196F3"), # Light Gray, Dark Gray, Blue
121
- ("#E8F4F9", "#1B4965", "#FFC107"), # Light Blue, Dark Blue, Yellow
122
- ("#FFF5E6", "#8B4513", "#4CAF50"), # Light Orange, Brown, Green
123
- ("#F0FFF0", "#228B22", "#9C27B0"), # Honeydew, Forest Green, Purple
124
- ("#FFF0F5", "#C71585", "#FF9800"), # Lavender, Pink, Orange
125
- ("#FFFFF0", "#8B8000", "#03A9F4"), # Ivory, Dark Yellow, Light Blue
126
- ("#F5FFFA", "#2E8B57", "#FF5722"), # Mint, Sea Green, Deep Orange
127
- ("#F8F8FF", "#483D8B", "#CDDC39"), # Ghost White, Dark Slate Blue, Lime
128
- ("#FFF5EE", "#FF4500", "#3F51B5") # Seashell, Orange Red, Indigo
129
- ]
130
-
131
- # Shape patterns
132
- self.shape_patterns = [
133
- (SVGShapeGenerator.draw_circles, "Circles"),
134
- (SVGShapeGenerator.draw_dots, "Dots"),
135
- (SVGShapeGenerator.draw_waves, "Waves"),
136
- (SVGShapeGenerator.draw_corners, "Corners")
137
- ]
138
-
139
- # Default design style
140
- self.design_style = {
141
- 'font_size': 48,
142
- 'image_size': (1400, 900), # Width x Height
143
- 'has_quotes': True
144
- }
145
-
146
- # Font configuration
147
- self.font_url = font_url
148
- self.font_path = None
149
- self._download_font()
150
- logger.info("TestimonialGenerator initialized successfully")
151
 
152
- def _download_font(self):
153
- """Download and store Poppins-Medium font"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
  try:
155
- self.font_path = os.path.join(SAVE_DIRS["fonts"], 'Poppins-Medium.ttf')
156
- if not os.path.exists(self.font_path):
157
- response = requests.get(self.font_url)
158
- with open(self.font_path, 'wb') as f:
159
- f.write(response.content)
160
- logger.info("Font downloaded successfully")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
  except Exception as e:
162
- logger.error(f"Error downloading font: {str(e)}")
163
- self.font_path = None
164
-
165
- def get_random_colors(self):
166
- """Get random background, text, and accent color combination"""
167
- return random.choice(self.color_schemes)
168
-
169
- def get_random_shape_pattern(self, selected_shapes):
170
- """Get selected shape patterns"""
171
- patterns = []
172
- for pattern, name in self.shape_patterns:
173
- if name in selected_shapes:
174
- patterns.append((pattern, name))
175
- return patterns
176
-
177
- def wrap_text(self, text, font_size, max_width, padding=100):
178
- """Wrap text to fit within maximum width with padding"""
179
- words = text.split()
180
- lines = []
181
- current_line = []
182
- effective_width = max_width - (2 * padding) # Simplified for SVG
183
-
184
- for word in words:
185
- current_line.append(word)
186
- line_width = len(' '.join(current_line)) * font_size * 0.6 # Approximation
187
-
188
- if line_width > effective_width:
189
- if len(current_line) == 1:
190
- lines.append(current_line[0])
191
- current_line = []
192
- else:
193
- current_line.pop()
194
- lines.append(' '.join(current_line))
195
- current_line = [word]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
196
 
197
- if current_line:
198
- lines.append(' '.join(current_line))
 
199
 
200
- return lines
201
 
202
- def render_svg(self, text, bg_color, text_color, accent_color, selected_shapes, font_size, has_quotes, custom_font_path=None):
203
- """Render testimonial SVG with shapes and text"""
204
- try:
205
- width, height = self.design_style['image_size']
206
- dwg = svgwrite.Drawing(size=(width, height))
207
-
208
- # Set background
209
- dwg.add(dwg.rect(insert=(0, 0), size=(width, height), fill=bg_color))
210
-
211
- # Add decorative shapes
212
- shape_patterns = self.get_random_shape_pattern(selected_shapes)
213
- for shape_func, shape_name in shape_patterns:
214
- shape_func(dwg, width, height, accent_color, opacity=0.5)
215
-
216
- # Add text
217
- if has_quotes:
218
- text = f'"{text}"'
219
-
220
- # Load font
221
- if custom_font_path:
222
- font_family = os.path.splitext(os.path.basename(custom_font_path))[0]
223
- with open(custom_font_path, 'rb') as f:
224
- font_data = f.read()
225
- font_base64 = base64.b64encode(font_data).decode('utf-8')
226
- font_style = f"""
227
- @font-face {{
228
- font-family: '{font_family}';
229
- src: url(data:font/truetype;charset=utf-8;base64,{font_base64}) format('truetype');
230
- }}
231
- """
232
- dwg.defs.add(dwg.style(font_style))
233
  else:
234
- font_family = 'Poppins-Medium'
235
-
236
- # Wrap text
237
- lines = self.wrap_text(text, font_size, width)
238
-
239
- # Calculate total text height
240
- total_text_height = len(lines) * font_size * 1.2
241
- current_y = (height - total_text_height) / 2
242
-
243
- for line in lines:
244
- text_width = len(line) * font_size * 0.6 # Approximation
245
- x = (width - text_width) / 2
246
- dwg.add(dwg.text(
247
- line,
248
- insert=(x, current_y + font_size),
249
- fill=text_color,
250
- font_size=font_size,
251
- font_family=font_family
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252
  ))
253
- current_y += font_size * 1.2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254
 
255
- return dwg.tostring()
256
- except Exception as e:
257
- logger.error(f"Error rendering SVG: {str(e)}")
258
- return None
 
 
259
 
260
- def generate_testimonial(self, topic):
261
- """Generate testimonial using Groq"""
262
- try:
263
- response = self.client.chat.completions.create(
264
- messages=[{
265
- "role": "system",
266
- "content": f"Generate a positive testimonial (2-3 sentences) about {topic}."
267
- }],
268
- model="mixtral-8x7b-32768",
269
- temperature=0.7,
270
- max_tokens=150
271
  )
272
- return response.choices[0].message.content.strip()
273
- except Exception as e:
274
- logger.error(f"Error generating testimonial: {str(e)}")
275
- return f"This {topic} exceeded all my expectations! The quality is outstanding, and the customer service team went above and beyond to ensure my satisfaction."
276
 
277
- def generate_and_render(topic, selected_shapes, font_size, has_quotes, custom_font_file):
278
- """Function to generate and render SVG testimonial based on user inputs"""
279
- generator = TestimonialGenerator()
 
 
 
280
 
281
- # Handle custom font upload
282
- if custom_font_file is not None:
283
- try:
284
- # Save custom font to fonts directory
285
- custom_font_path = os.path.join(SAVE_DIRS["fonts"], custom_font_file.name)
286
- with open(custom_font_path, 'wb') as f:
287
- f.write(custom_font_file.read())
288
- logger.info("Custom font uploaded and saved successfully")
289
- except Exception as e:
290
- logger.error(f"Error saving custom font: {str(e)}")
291
- custom_font_path = None
292
- else:
293
- custom_font_path = None
294
-
295
- # Generate testimonial text
296
- testimonial = generator.generate_testimonial(topic)
297
-
298
- # Get random color scheme
299
- bg_color, text_color, accent_color = generator.get_random_colors()
300
-
301
- # Render SVG
302
- svg_content = generator.render_svg(
303
- text=testimonial,
304
- bg_color=bg_color,
305
- text_color=text_color,
306
- accent_color=accent_color,
307
- selected_shapes=selected_shapes,
308
- font_size=font_size,
309
- has_quotes=has_quotes,
310
- custom_font_path=custom_font_path
311
- )
312
 
313
- if svg_content:
314
- # Save SVG
315
- svg_filename = f"testimonial_{datetime.now().strftime('%Y%m%d_%H%M%S')}.svg"
316
- svg_path = os.path.join(SAVE_DIRS['images'], svg_filename)
317
- with open(svg_path, 'w') as f:
318
- f.write(svg_content)
319
- logger.info(f"SVG saved to {svg_path}")
320
-
321
- # Encode SVG for display
322
- svg_base64 = base64.b64encode(svg_content.encode('utf-8')).decode('utf-8')
323
- svg_data_uri = f"data:image/svg+xml;base64,{svg_base64}"
324
-
325
- return f'<img src="{svg_data_uri}" style="max-width:100%;">', svg_path
326
- else:
327
- return "Failed to generate SVG.", None
328
-
329
- # Initialize Gradio Interface
330
- iface = gr.Interface(
331
- fn=generate_and_render,
332
- inputs=[
333
- gr.Textbox(label="Testimonial Topic", placeholder="Enter the topic for the testimonial...", lines=1),
334
- gr.CheckboxGroup(
335
- label="Select Shape Patterns",
336
- choices=["Circles", "Dots", "Waves", "Corners"],
337
- value=["Circles", "Dots"] # Replaced 'default' with 'value'
338
- ),
339
- gr.Slider(label="Font Size", minimum=24, maximum=72, step=2, value=48),
340
- gr.Checkbox(label="Include Quotes", value=True),
341
- gr.File(label="Upload Custom Font (Optional)", file_types=["ttf", "otf"])
342
- ],
343
- outputs=[
344
- gr.HTML(label="Generated Testimonial SVG"),
345
- gr.File(label="Download SVG")
346
- ],
347
- title="Testimonial Generator",
348
- description="""
349
- Generate personalized testimonials with customizable designs.
350
- - **Testimonial Topic**: The subject of the testimonial.
351
- - **Shape Patterns**: Select which decorative shapes to include.
352
- - **Font Size**: Adjust the size of the testimonial text.
353
- - **Include Quotes**: Add quotation marks around the testimonial.
354
- - **Custom Font**: Upload a custom `.ttf` or `.otf` font file for the text.
355
- """,
356
- allow_flagging="never"
357
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
358
 
359
- if __name__ == "__main__":
360
- iface.launch()
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import openai
3
  import os
4
+ from dotenv import load_dotenv
5
  import logging
6
+ import datetime
7
+ import json
8
+ import re
9
+ import random
10
+
11
+ # Set up logging with more detailed configuration
12
+ log_dir = "logs"
13
+ if not os.path.exists(log_dir):
14
+ os.makedirs(log_dir)
15
 
16
+ log_filename = os.path.join(log_dir, f"svg_generator_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}.log")
17
  logging.basicConfig(
18
+ filename=log_filename,
19
  level=logging.INFO,
20
+ format='%(asctime)s - %(levelname)s - [%(filename)s:%(lineno)d] - %(message)s'
 
 
 
 
21
  )
22
+
23
+ # Add console handler to see logs in terminal
24
+ console_handler = logging.StreamHandler()
25
+ console_handler.setLevel(logging.INFO)
26
+ console_formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
27
+ console_handler.setFormatter(console_formatter)
28
+ logging.getLogger().addHandler(console_handler)
29
+
30
+ # Load environment variables
31
+ load_dotenv()
32
+ logging.info("Environment variables loaded")
33
+
34
+ # Configure OpenAI API
35
+ api_key = os.getenv("OPENAI_API_KEY")
36
+ if not api_key:
37
+ logging.error("OPENAI_API_KEY not found in environment variables!")
38
+ raise ValueError("OPENAI_API_KEY not found!")
39
+
40
+ client = openai.OpenAI(api_key=api_key)
41
+ logging.info("OpenAI client initialized successfully")
42
+
43
+ def clean_svg_content(content):
44
+ """Clean and validate SVG content"""
45
+ # Remove any leading/trailing whitespace
46
+ content = content.strip()
47
+
48
+ # Log original content for debugging
49
+ logging.info(f"Original content starts with: {content[:100]}...")
50
+
51
+ # Remove XML declaration if present
52
+ content = re.sub(r'<\?xml[^>]+\?>\s*', '', content)
53
+
54
+ # Remove DOCTYPE if present
55
+ content = re.sub(r'<!DOCTYPE[^>]+>\s*', '', content)
56
+
57
+ # Remove any comments
58
+ content = re.sub(r'<!--[\s\S]*?-->\s*', '', content)
59
+
60
+ # Remove any empty lines
61
+ content = '\n'.join(line for line in content.splitlines() if line.strip())
62
+
63
+ # Log cleaned content
64
+ logging.info(f"Cleaned content starts with: {content[:100]}...")
65
+
66
+ return content
67
+
68
+ def validate_svg(content):
69
+ """Validate SVG content"""
70
+ # Check if content starts with <svg tag (allowing for attributes)
71
+ if not re.match(r'\s*<svg[\s>]', content):
72
+ logging.warning(f"Content doesn't start with SVG tag. Content starts with: {content[:100]}")
73
+ return False
74
+
75
+ # Check if content has matching closing tag
76
+ if not content.strip().endswith('</svg>'):
77
+ logging.warning("Content doesn't end with closing SVG tag")
78
+ return False
79
+
80
+ return True
81
+ def generate_svg(prompt):
82
+ """Generate SVG using the fine-tuned GPT-4 model"""
83
+ try:
84
+ logging.info(f"Sending request to OpenAI API with prompt: {prompt[:100]}...")
85
+ logging.info(f"Using model: ft:gpt-4o-mini-2024-07-18:personal::AyNMN2ax")
86
 
87
+ response = client.chat.completions.create(
88
+ model="ft:gpt-4o-mini-2024-07-18:personal::AyNMN2ax",
89
+ messages=[
90
+ {"role": "system", "content": """in this add this Create a well-aligned and meaningful SVG generator prompt. Ensure it includes appropriate alignment and content instructions.
91
+
92
+ # Output Format
93
+
94
+ The SVG should be generated with structured alignment and include meaningful attributes such as colors, dimensions, and positioning.
95
+
96
+ # Steps [optional]
97
+
98
+ 1. Define the shapes and their attributes (e.g., circles, rectangles).
99
+ 2. Set the colors and dimensions.
100
+ 3. Align the objects to create a cohesive design.
101
+ 4. Review and adjust for meaningfulness and symmetry.
102
+
103
+ # Examples [optional]
104
+
105
+ Example Input:
106
+ - Shapes: Circle, Rectangle
107
+ - Colors: Blue, Red
108
+ - Sizes: 100x100, 50x50
109
+ - Positioning: Center
110
+
111
+ Example Output:
112
+ ```svg
113
+ <svg width="200" height="200">
114
+ <circle cx="100" cy="100" r="50" fill="blue" />
115
+ <rect x="75" y="75" width="50" height="50" fill="red"/>
116
+ </svg>
117
+ ```
118
+
119
+ # Notes [optional]
120
+
121
+ - Ensure the SVG is valid and adheres to SVG standards.
122
+ - Ensure in output only generate the svg only in svg you can create comment it's okay
123
+ - Consider accessibility aspects such as color contrast.
124
+ - Review the design for visual balance and clarity.
125
+ - IMPORTANT: Return ONLY the raw SVG code without any markdown formatting or explanations. The response should start with <svg and end with </svg>."""},
126
+ {"role": "user", "content": prompt}
127
+ ],
128
+ temperature=1, # Reduced for more consistent output
129
+ max_tokens=2000,
130
+ )
131
+ # Log the response details
132
+ logging.info(f"Response received from OpenAI API")
133
+ logging.info(f"Response finish reason: {response.choices[0].finish_reason}")
134
 
135
+ # Get and clean the SVG content
136
+ svg_content = response.choices[0].message.content
137
+ logging.info(f"Raw SVG length: {len(svg_content)} characters")
 
 
 
 
 
 
 
138
 
139
+ # Clean the SVG content
140
+ cleaned_svg = clean_svg_content(svg_content)
141
+ logging.info(f"Cleaned SVG length: {len(cleaned_svg)} characters")
 
 
 
 
 
 
 
 
 
 
142
 
143
+ # Validate the cleaned SVG
144
+ if not validate_svg(cleaned_svg):
145
+ error_msg = "Invalid SVG format received from API"
146
+ logging.error(error_msg)
147
+ return f"""<svg width="400" height="100" xmlns="http://www.w3.org/2000/svg">
148
+ <rect width="100%" height="100%" fill="#ffebee"/>
149
+ <text x="10" y="40" fill="red" font-family="Arial">Error: {error_msg}</text>
150
+ <text x="10" y="80" fill="#666" font-family="Arial" font-size="12">
151
+ Please try again with a different prompt
152
+ </text>
153
+ </svg>"""
 
 
 
 
 
154
 
155
+ return cleaned_svg
156
+
157
+ except openai.APIError as e:
158
+ error_msg = f"OpenAI API Error: {str(e)}"
159
+ logging.error(error_msg)
160
+ return f"""<svg width="400" height="100" xmlns="http://www.w3.org/2000/svg">
161
+ <rect width="100%" height="100%" fill="#ffebee"/>
162
+ <text x="10" y="40" fill="red" font-family="Arial">{error_msg}</text>
163
+ </svg>"""
164
+ except openai.APIConnectionError as e:
165
+ error_msg = f"Connection Error: {str(e)}"
166
+ logging.error(error_msg)
167
+ return f"""<svg width="400" height="100" xmlns="http://www.w3.org/2000/svg">
168
+ <rect width="100%" height="100%" fill="#ffebee"/>
169
+ <text x="10" y="40" fill="red" font-family="Arial">{error_msg}</text>
170
+ </svg>"""
171
+ except openai.RateLimitError as e:
172
+ error_msg = f"Rate Limit Error: {str(e)}"
173
+ logging.error(error_msg)
174
+ return f"""<svg width="400" height="100" xmlns="http://www.w3.org/2000/svg">
175
+ <rect width="100%" height="100%" fill="#ffebee"/>
176
+ <text x="10" y="40" fill="red" font-family="Arial">{error_msg}</text>
177
+ </svg>"""
178
+ except Exception as e:
179
+ error_msg = f"Unexpected Error: {str(e)}"
180
+ logging.error(error_msg, exc_info=True)
181
+ return f"""<svg width="400" height="100" xmlns="http://www.w3.org/2000/svg">
182
+ <rect width="100%" height="100%" fill="#ffebee"/>
183
+ <text x="10" y="40" fill="red" font-family="Arial">{error_msg}</text>
184
+ </svg>"""
185
+
186
+ def create_preview_svg(svg_content):
187
+ """Create a preview version of the SVG with proper sizing"""
188
+ # Force width and height to 1080 for full size preview
189
+ svg_content = re.sub(r'width="[^"]+"', 'width="1080"', svg_content)
190
+ svg_content = re.sub(r'height="[^"]+"', 'height="1080"', svg_content)
191
+
192
+ # Ensure viewBox is present
193
+ if 'viewBox' not in svg_content:
194
+ svg_content = svg_content.replace('<svg', '<svg viewBox="0 0 1080 1080"', 1)
195
+
196
+ return svg_content
197
+
198
+ def create_fullview_html(svg):
199
+ """Create HTML for full-view modal with proper sizing"""
200
+ return f"""
201
+ <div style="width:1080px; height:1080px; overflow:auto; background-color:#f0f0f0; padding:20px;">
202
+ {svg}
203
+ </div>
204
+ """
205
+ def generate_similar_prompts(example_prompt):
206
+ """Generate 10 similar testimonial prompts based on an example prompt using GPT-4 mini"""
207
+ system_prompt = """You are a creative testimonial prompt generator. Based on the following example prompt,
208
+ generate 10 unique testimonial prompts that start with 'Create' and are similar in style but with variations in:"""
209
+
210
+ user_prompt = f"Example prompt: {example_prompt}\n\nGenerate 10 similar prompts that start with 'Create', with good alignment and default positioning"
211
+ try:
212
+ logging.info("Sending request to OpenAI API for similar prompts...")
213
+ response = client.chat.completions.create(
214
+ model="gpt-4o-mini-2024-07-18",
215
+ messages=[
216
+ {"role": "system", "content": system_prompt},
217
+ {"role": "user", "content": user_prompt}
218
+ ],
219
+ temperature=0.7,
220
+ max_tokens=500
221
+ )
222
+ prompts_text = response.choices[0].message.content.strip()
223
+ logging.info("Received similar prompts from OpenAI API")
224
+ prompts_list = [line.strip() for line in prompts_text.splitlines() if line.strip()]
225
+
226
+ # Ensure each prompt includes quality requirements and SVG code request
227
+ quality_prompts = []
228
+ for prompt in prompts_list:
229
+ if "good alignment" not in prompt.lower() and "default positioning" not in prompt.lower():
230
+ prompt += " create svg code with good alignment, default word positioning and high SVG quality. Please provide complete SVG code."
231
+ quality_prompts.append(prompt)
232
+
233
+ if len(quality_prompts) < 10:
234
+ extra_count = 10 - len(quality_prompts)
235
+ 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)]
236
+ quality_prompts += unique_prompts
237
+ else:
238
+ quality_prompts = quality_prompts[:10]
239
 
240
+ # Add default SVG code request to all prompts
241
+ final_prompts = []
242
+ for prompt in quality_prompts:
243
+ if "create svg code" not in prompt.lower():
244
+ prompt += " Please create complete SVG code with proper structure and elements."
245
+ final_prompts.append(prompt)
246
 
247
+ return final_prompts
248
+
249
+ except Exception as e:
250
+ error_msg = f"Error generating similar prompts: {str(e)}"
251
+ logging.error(error_msg, exc_info=True)
252
+ 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)]
253
+
254
+ def generate_random_prompt(user_prompt=None):
255
+ """
256
+ Generate a unique prompt based on user's input prompt.
257
+ If no prompt is provided, use a default example.
258
+ Ensures all generated prompts maintain quality standards.
259
+ """
260
+ if not user_prompt:
261
+ user_prompt = "Design a modern testimonial with a clean layout, balanced typography, and vibrant color accents."
262
+
263
+ # Add quality requirements to the base prompt
264
+ base_prompt = f"{user_prompt} The design must have good alignment, balanced composition, and professional SVG quality."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
265
 
266
+ # Generate variations based on the enhanced base prompt
267
+ prompts = generate_similar_prompts(base_prompt)
268
+
269
+ # Ensure each prompt includes quality requirements
270
+ quality_prompts = []
271
+ for prompt in prompts:
272
+ if "good alignment" not in prompt.lower() and "svg quality" not in prompt.lower():
273
+ prompt += " Ensure good alignment and high SVG quality."
274
+ quality_prompts.append(prompt)
275
+
276
+ return random.choice(quality_prompts)
277
+
278
+ def process_all_prompts(*prompts):
279
+ """Process all prompts and return SVG results with preview and full-view versions"""
280
+ preview_results = []
281
+ fullview_results = []
282
+ logging.info(f"Starting to process {len(prompts)} prompts")
283
+
284
+ for i, prompt in enumerate(prompts, 1):
285
+ logging.info(f"\n{'='*50}")
286
+ logging.info(f"Processing prompt {i} of {len(prompts)}")
287
+
288
  try:
289
+ if prompt.strip():
290
+ modified_prompt = prompt.strip() + " The design must have good alignment and be visually appealing."
291
+ logging.info(f"Prompt {i} content: {modified_prompt[:100]}...")
292
+ svg = generate_svg(modified_prompt)
293
+ preview_svg = create_preview_svg(svg)
294
+ logging.info(f"Successfully generated SVG for prompt {i}")
295
+ logging.info(f"SVG size: {len(svg)} characters")
296
+
297
+ preview_results.append(preview_svg)
298
+ fullview_results.append(svg)
299
+ else:
300
+ default_svg = """<svg width="300" height="300" xmlns="http://www.w3.org/2000/svg">
301
+ <rect width="100%" height="100%" fill="#f5f5f5"/>
302
+ <text x="50%" y="50%" fill="#666" font-family="Arial" text-anchor="middle">
303
+ No prompt provided
304
+ </text>
305
+ </svg>"""
306
+ logging.info(f"Empty prompt {i} received - using default SVG")
307
+ preview_results.append(default_svg)
308
+ fullview_results.append(default_svg)
309
  except Exception as e:
310
+ error_msg = f"Error processing prompt {i}: {str(e)}"
311
+ logging.error(error_msg, exc_info=True)
312
+ error_svg = f"""<svg width="300" height="300" xmlns="http://www.w3.org/2000/svg">
313
+ <rect width="100%" height="100%" fill="#ffebee"/>
314
+ <text x="50%" y="40%" fill="red" font-family="Arial" text-anchor="middle">
315
+ Error generating SVG
316
+ </text>
317
+ <text x="50%" y="60%" fill="#666" font-family="Arial" font-size="12" text-anchor="middle">
318
+ {error_msg}
319
+ </text>
320
+ </svg>"""
321
+ preview_results.append(error_svg)
322
+ fullview_results.append(error_svg)
323
+
324
+ logging.info(f"Completed processing prompt {i}")
325
+ logging.info(f"{'='*50}\n")
326
+
327
+ logging.info(f"Completed processing all {len(prompts)} prompts")
328
+ return tuple(preview_results) + (fullview_results,)
329
+
330
+ def generate_svg_wrapper(prompt):
331
+ """
332
+ Wrapper function to handle SVG generation and create preview
333
+ Returns the preview SVG, full SVG, and a status message for display
334
+ """
335
+ if not prompt:
336
+ return None, None, "❌ Please enter a prompt first!"
337
+ modified_prompt = prompt.strip() + " The design must have good alignment and be visually appealing."
338
+ svg = generate_svg(modified_prompt)
339
+ preview_svg = create_preview_svg(svg)
340
+ return preview_svg, svg, "βœ… Generated SVG for prompt!"
341
+
342
+ def generate_svg_and_show_code_fn(prompt):
343
+ """Wrapper function to generate an SVG and immediately show the SVG code below the preview."""
344
+ preview, code, status = generate_svg_wrapper(prompt)
345
+ return preview, gr.update(value=code, visible=True), status
346
+
347
+ def generate_multiple_svgs(*args):
348
+ # Use the values from prompt boxes instead of generating new ones
349
+ prompts = [arg for arg in args if arg and isinstance(arg, str)]
350
+ num_galleries = len(svg_galleries)
351
+ num_code_boxes = len(code_boxes)
352
+
353
+ if not prompts:
354
+ empty_preview = '<div style="width:1080px; height:1080px; display:flex; justify-content:center; align-items:center; background:#f5f5f5;">Generate prompts first</div>'
355
+ outputs = []
356
+
357
+ # Add status and container updates
358
+ outputs.append("❌ Please generate and edit prompts first before generating designs!") # status message
359
+ outputs.append(gr.update(visible=False)) # multi_svg_container
360
+ outputs.append(gr.update(visible=True)) # single_svg_container
361
+
362
+ # Add gallery outputs with visibility updates
363
+ for _ in range(num_galleries):
364
+ outputs.append(gr.update(value=empty_preview, visible=False))
365
 
366
+ # Add code outputs with visibility updates
367
+ for _ in range(num_code_boxes):
368
+ outputs.append(gr.update(value="", visible=False))
369
 
370
+ return outputs
371
 
372
+ try:
373
+ logging.info(f"Generating SVGs for {len(prompts)} prompts")
374
+ gallery_outputs = []
375
+ code_outputs = []
376
+
377
+ for prompt in prompts:
378
+ if prompt.strip():
379
+ preview_svg, full_svg, _ = generate_svg_wrapper(prompt)
380
+ gallery_outputs.append(gr.update(value=preview_svg, visible=True))
381
+ code_outputs.append(gr.update(value=full_svg, visible=False))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
382
  else:
383
+ 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))
384
+ code_outputs.append(gr.update(value="", visible=False))
385
+
386
+ outputs = []
387
+
388
+ # Add status and container updates
389
+ outputs.append("βœ… Generated designs based on your edited prompts!") # status message
390
+ outputs.append(gr.update(visible=True)) # multi_svg_container
391
+ outputs.append(gr.update(visible=False)) # single_svg_container
392
+
393
+ # Add gallery outputs
394
+ for i in range(num_galleries):
395
+ if i < len(gallery_outputs):
396
+ outputs.append(gallery_outputs[i])
397
+ else:
398
+ 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))
399
+
400
+ # Add code outputs
401
+ for i in range(num_code_boxes):
402
+ if i < len(code_outputs):
403
+ outputs.append(code_outputs[i])
404
+ else:
405
+ outputs.append(gr.update(value="", visible=False))
406
+
407
+ logging.info("Successfully generated all SVGs")
408
+ return outputs
409
+
410
+ except Exception as e:
411
+ error_msg = f"Error generating SVGs: {str(e)}"
412
+ logging.error(error_msg, exc_info=True)
413
+ error_preview = '<div style="width:1080px; height:1080px; display:flex; justify-content:center; align-items:center; background:#ffebee;">Error generating SVG</div>'
414
+
415
+ outputs = []
416
+
417
+ # Add status and container updates
418
+ outputs.append(f"❌ {error_msg}") # status message
419
+ outputs.append(gr.update(visible=False)) # multi_svg_container
420
+ outputs.append(gr.update(visible=True)) # single_svg_container
421
+
422
+ # Add gallery outputs with visibility updates
423
+ for _ in range(num_galleries):
424
+ outputs.append(gr.update(value=error_preview, visible=False))
425
+
426
+ # Add code outputs with visibility updates
427
+ for _ in range(num_code_boxes):
428
+ outputs.append(gr.update(value="", visible=False))
429
+
430
+ return outputs
431
+
432
+ # Create the Gradio interface
433
+ with gr.Blocks(theme=gr.themes.Soft()) as app:
434
+ gr.Markdown("# SVG Generator with Similar Prompt Generation")
435
+
436
+ gr.Markdown("### Step 1: Enter an example prompt to generate similar prompts")
437
+ example_prompt_input = gr.Textbox(label="Example Prompt", placeholder="Enter an example testimonial prompt here...", lines=3)
438
+ generate_examples_btn = gr.Button("Generate 10 Similar Prompts")
439
+
440
+ gr.Markdown("### Step 2: Review and edit the generated prompts")
441
+ prompts = [gr.Textbox(label=f"Prompt {i+1}", placeholder=f"Generated prompt {i+1}...") for i in range(10)]
442
+
443
+ # When button is clicked, populate the 10 prompt textboxes
444
+ generate_examples_btn.click(fn=generate_similar_prompts, inputs=example_prompt_input, outputs=prompts)
445
+
446
+ gr.Markdown("### Step 3: Generate SVGs for the above prompts")
447
+
448
+ generate_btn = gr.Button("Generate SVGs", variant="primary", size="lg")
449
+
450
+ # Store full-view SVGs
451
+ fullview_svgs = gr.State([])
452
+
453
+ preview_outputs = []
454
+
455
+ # Create grid layout for SVG previews
456
+ with gr.Row():
457
+ with gr.Column(scale=1):
458
+ for i in range(0, 5): # First column
459
+ with gr.Group():
460
+ preview = gr.HTML(label=f"SVG {i+1}", container=True)
461
+ preview_outputs.append(preview)
462
+
463
+ # Add a button that opens the full view in a new tab
464
+ def create_view_fn(index):
465
+ def view_fn(svgs):
466
+ if svgs and len(svgs) > index:
467
+ return f"""
468
+ <!DOCTYPE html>
469
+ <html>
470
+ <head>
471
+ <title>Full Size SVG {index + 1}</title>
472
+ <style>
473
+ body {{
474
+ margin: 0;
475
+ padding: 20px;
476
+ display: flex;
477
+ justify-content: center;
478
+ align-items: flex-start;
479
+ min-height: 100vh;
480
+ background-color: #f0f0f0;
481
+ gap: 20px;
482
+ }}
483
+ .svg-container {{
484
+ width: 1080px;
485
+ height: 1080px;
486
+ background-color: white;
487
+ padding: 20px;
488
+ border-radius: 10px;
489
+ box-shadow: 0 0 20px rgba(0,0,0,0.1);
490
+ }}
491
+ .code-container {{
492
+ width: 600px;
493
+ background-color: white;
494
+ padding: 20px;
495
+ border-radius: 10px;
496
+ box-shadow: 0 0 20px rgba(0,0,0,0.1);
497
+ }}
498
+ pre {{
499
+ white-space: pre-wrap;
500
+ word-wrap: break-word;
501
+ background-color: #f5f5f5;
502
+ padding: 15px;
503
+ border-radius: 5px;
504
+ margin: 0;
505
+ font-family: monospace;
506
+ font-size: 14px;
507
+ line-height: 1.4;
508
+ max-height: 1080px;
509
+ overflow-y: auto;
510
+ }}
511
+ .copy-button {{
512
+ margin-top: 10px;
513
+ padding: 8px 16px;
514
+ background-color: #4CAF50;
515
+ color: white;
516
+ border: none;
517
+ border-radius: 4px;
518
+ cursor: pointer;
519
+ font-size: 14px;
520
+ }}
521
+ .copy-button:hover {{
522
+ background-color: #45a049;
523
+ }}
524
+ </style>
525
+ </head>
526
+ <body>
527
+ <div class="svg-container">
528
+ {svgs[index]}
529
+ </div>
530
+ <div class="code-container">
531
+ <h3>SVG Code</h3>
532
+ <pre id="svg-code">{svgs[index].replace('<', '&lt;').replace('>', '&gt;')}</pre>
533
+ <button class="copy-button" onclick="copyCode()">Copy SVG Code</button>
534
+ </div>
535
+ <script>
536
+ function copyCode() {{
537
+ const code = document.getElementById('svg-code').textContent;
538
+ navigator.clipboard.writeText(code).then(() => {{
539
+ const btn = document.querySelector('.copy-button');
540
+ btn.textContent = 'Copied!';
541
+ setTimeout(() => btn.textContent = 'Copy SVG Code', 2000);
542
+ }});
543
+ }}
544
+ </script>
545
+ </body>
546
+ </html>
547
+ """
548
+ return ""
549
+ return view_fn
550
+
551
+ with gr.Row():
552
+ view_btn = gr.Button(f"View Full Size {i+1}", size="sm")
553
+ full_view = gr.HTML(visible=False)
554
+
555
+ view_btn.click(
556
+ fn=create_view_fn(i),
557
+ inputs=[fullview_svgs],
558
+ outputs=[full_view],
559
+ js="""
560
+ async function(svg_html) {
561
+ if (svg_html) {
562
+ const win = window.open("", "_blank");
563
+ win.document.write(svg_html);
564
+ }
565
+ return "";
566
+ }
567
+ """
568
+ )
569
+
570
+ with gr.Column(scale=1):
571
+ for i in range(5, 10): # Second column
572
+ with gr.Group():
573
+ preview = gr.HTML(label=f"SVG {i+1}", container=True)
574
+ preview_outputs.append(preview)
575
+
576
+ with gr.Row():
577
+ view_btn = gr.Button(f"View Full Size {i+1}", size="sm")
578
+ full_view = gr.HTML(visible=False)
579
+
580
+ view_btn.click(
581
+ fn=create_view_fn(i),
582
+ inputs=[fullview_svgs],
583
+ outputs=[full_view],
584
+ js="""
585
+ async function(svg_html) {
586
+ if (svg_html) {
587
+ const win = window.open("", "_blank");
588
+ win.document.write(svg_html);
589
+ }
590
+ return "";
591
+ }
592
+ """
593
+ )
594
+
595
+ # Add some CSS to style the previews
596
+ gr.HTML("""
597
+ <style>
598
+ .svg-preview {
599
+ border: 1px solid #ddd;
600
+ border-radius: 8px;
601
+ padding: 10px;
602
+ margin: 10px auto;
603
+ background: white;
604
+ width: 1080px !important;
605
+ height: 1080px !important;
606
+ display: flex;
607
+ justify-content: center;
608
+ align-items: center;
609
+ }
610
+ .preview-container {
611
+ display: flex;
612
+ flex-direction: column;
613
+ gap: 10px;
614
+ margin: 10px auto;
615
+ width: 1080px;
616
+ }
617
+ .gradio-html {
618
+ display: flex;
619
+ justify-content: center;
620
+ align-items: center;
621
+ }
622
+ .gradio-html > div {
623
+ width: 1080px !important;
624
+ height: 1080px !important;
625
+ }
626
+ .gradio-html svg {
627
+ width: 1080px !important;
628
+ height: 1080px !important;
629
+ }
630
+ </style>
631
+ """)
632
+
633
+ generate_btn.click(
634
+ fn=process_all_prompts,
635
+ inputs=prompts,
636
+ outputs=preview_outputs + [fullview_svgs]
637
+ )
638
+
639
+ # Launch the app
640
+ if __name__ == "__main__":
641
+ logging.info("Starting SVG Generator application")
642
+ try:
643
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
644
+ gr.Markdown("""
645
+ # 🎨 SVG Testimonial Generator
646
+
647
+ ### How to use:
648
+ 1. Enter your own prompt OR generate a random prompt
649
+ 2. Review the prompt and generate designs
650
+ 3. View, download, or check the code for each design
651
+ """)
652
+
653
+ # Define containers and lists first
654
+ multi_svg_container = gr.Row(visible=False)
655
+ single_svg_container = gr.Row()
656
+ svg_galleries = []
657
+ code_boxes = []
658
+ code_visibilities = [] # Initialize code_visibilities list
659
+
660
+ # Create galleries, code boxes, and visibility states
661
+ for i in range(10):
662
+ svg_galleries.append(gr.HTML(
663
+ label=f"Preview {i+1}",
664
+ 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>',
665
+ visible=False
666
  ))
667
+ code_box = gr.Textbox(
668
+ label=f"SVG Code {i+1}",
669
+ lines=5,
670
+ visible=False,
671
+ show_copy_button=True
672
+ )
673
+ code_boxes.append(code_box)
674
+ code_visibilities.append(gr.update(visible=False)) # Add visibility state for each code box
675
+
676
+ with gr.Row():
677
+ with gr.Column(scale=3):
678
+ prompt_input = gr.Textbox(
679
+ label="✍️ Enter Your Design Prompt",
680
+ lines=2,
681
+ placeholder="Example: Design a modern testimonial with a dark background, white text, and customer quote from John Doe about excellent service."
682
+ )
683
+
684
+ with gr.Row():
685
+ with gr.Column(scale=1):
686
+ random_prompt_btn = gr.Button("🎲 Generate Random Prompt", variant="secondary", size="lg")
687
+ with gr.Column(scale=1):
688
+ generate_designs_btn = gr.Button("🎨 Generate 10 Designs", variant="primary", size="lg")
689
+ with gr.Column(scale=1):
690
+ generate_single_btn = gr.Button("πŸš€ Generate Single SVG", variant="primary", size="lg")
691
+
692
+ # Status message for user feedback
693
+ status_message = gr.Markdown("")
694
+
695
+ # Container for editable prompts
696
+ with gr.Row() as prompts_container:
697
+ with gr.Column():
698
+ prompt_boxes = []
699
+ svg_previews = []
700
+ generate_buttons = [] # Store generate buttons
701
+ for i in range(10):
702
+ with gr.Row():
703
+ prompt_boxes.append(gr.Textbox(
704
+ label=f"✍️ Prompt {i+1}",
705
+ lines=2,
706
+ interactive=True,
707
+ visible=False
708
+ ))
709
+ gen_btn = gr.Button(f"🎨 Generate SVG {i+1}", visible=False)
710
+ generate_buttons.append(gen_btn) # Store button reference
711
+ svg_preview = gr.HTML(visible=False)
712
+ svg_previews.append(svg_preview)
713
+
714
+ def create_generate_fn(index):
715
+ def generate_fn(prompt):
716
+ if not prompt:
717
+ return gr.update(visible=False), "❌ Please enter a prompt first!"
718
+ try:
719
+ svg_content = generate_svg(prompt)
720
+ preview_svg = create_preview_svg(svg_content)
721
+ return gr.update(value=preview_svg, visible=True), f"βœ… Generated SVG for prompt {index + 1}!"
722
+ except Exception as e:
723
+ return gr.update(visible=False), f"❌ Error generating SVG: {str(e)}"
724
+ return generate_fn
725
+
726
+ gen_btn.click(
727
+ fn=create_generate_fn(i),
728
+ inputs=[prompt_boxes[i]],
729
+ outputs=[svg_previews[i], status_message]
730
+ )
731
+
732
+ # Add Generate All button
733
+ with gr.Row():
734
+ generate_all_btn = gr.Button("🎨 Generate All SVGs", variant="primary", size="lg", visible=False)
735
+
736
+ def generate_and_show_prompts(current_prompt):
737
+ prompts = generate_similar_prompts(current_prompt) if current_prompt else [generate_random_prompt() for _ in range(10)]
738
+ outputs = []
739
+
740
+ # Add prompt box updates
741
+ for prompt in prompts:
742
+ outputs.append(gr.update(value=prompt, visible=True))
743
+
744
+ # Add status message
745
+ outputs.append("βœ… Generated prompts! Click individual Generate buttons or Generate All to create designs!")
746
+
747
+ # Add generate all button visibility
748
+ outputs.append(gr.update(visible=True))
749
+
750
+ # Add generate button visibilities
751
+ for _ in range(len(generate_buttons)):
752
+ outputs.append(gr.update(visible=True))
753
+
754
+ return outputs
755
 
756
+ # Event handler for random prompt generation
757
+ random_prompt_btn.click(
758
+ fn=generate_and_show_prompts,
759
+ inputs=[prompt_input],
760
+ outputs=prompt_boxes + [status_message, generate_all_btn] + generate_buttons
761
+ )
762
 
763
+ # Event handler for Generate All button
764
+ generate_all_btn.click(
765
+ fn=generate_multiple_svgs,
766
+ inputs=prompt_boxes,
767
+ outputs=[status_message, multi_svg_container, single_svg_container] + svg_galleries + code_boxes
 
 
 
 
 
 
768
  )
 
 
 
 
769
 
770
+ # Event handler for Generate Designs button
771
+ generate_designs_btn.click(
772
+ fn=generate_multiple_svgs,
773
+ inputs=prompt_boxes,
774
+ outputs=[status_message, multi_svg_container, single_svg_container] + svg_galleries + code_boxes
775
+ )
776
 
777
+ # Single SVG preview container
778
+ with gr.Row() as single_svg_container:
779
+ with gr.Column(min_width=1100):
780
+ svg_preview = gr.HTML(
781
+ label="Preview",
782
+ 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>'
783
+ )
784
+ svg_code_box = gr.Textbox(
785
+ label="SVG Code",
786
+ lines=10,
787
+ visible=False,
788
+ show_copy_button=True
789
+ )
790
+ download_btn = gr.Button("πŸ’Ύ Download", variant="secondary")
791
+ file_output = gr.File(label="Download", visible=False)
792
+
793
+ # Now, register the single SVG generation click event AFTER svg_code_box is defined:
794
+ generate_single_btn.click(
795
+ fn=generate_svg_and_show_code_fn,
796
+ inputs=[prompt_input],
797
+ outputs=[svg_preview, svg_code_box, status_message]
798
+ )
 
 
 
 
 
 
 
 
 
799
 
800
+ # Container for random prompts display (can be removed since we now use textboxes)
801
+ with gr.Row(visible=False) as random_prompts_container:
802
+ random_prompts_box = gr.Dataframe(
803
+ headers=["#", "Random Prompts"],
804
+ label="Generated Random Prompts",
805
+ interactive=False
806
+ )
807
+
808
+ # Container for multiple SVGs
809
+ with gr.Row(visible=False) as multi_svg_container:
810
+ with gr.Column(min_width=1100):
811
+ svg_galleries = []
812
+ code_boxes = []
813
+ code_visibilities = []
814
+ view_code_buttons = []
815
+ download_buttons = [] # Initialize download_buttons list
816
+
817
+ for i in range(10):
818
+ with gr.Group():
819
+ gr.Markdown(f"### Design {i+1}")
820
+ # Preview container with fixed size
821
+ with gr.Column(min_width=1080):
822
+ # Preview
823
+ svg_galleries.append(gr.HTML(
824
+ label=f"Preview {i+1}",
825
+ 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>'
826
+ ))
827
+ with gr.Row():
828
+ # View Code button
829
+ view_code_btn = gr.Button(f"πŸ“ View Code {i+1}", variant="secondary")
830
+ view_code_buttons.append(view_code_btn)
831
+ # Download button
832
+ download_btn = gr.Button(f"πŸ’Ύ Download {i+1}", variant="secondary")
833
+ # Code view
834
+ code_box = gr.Textbox(
835
+ label=f"SVG Code {i+1}",
836
+ lines=5,
837
+ visible=False,
838
+ show_copy_button=True
839
+ )
840
+ code_boxes.append(code_box)
841
+ code_visibilities.append(gr.update(visible=False))
842
+ # Hidden file output
843
+ file_output = gr.File(label=f"Download {i+1}", visible=False)
844
+ download_buttons.append((download_btn, file_output))
845
+ # Add separator
846
+ gr.Markdown("---")
847
+
848
+ def toggle_code_visibility(evt: gr.SelectData):
849
+ """Toggle visibility of code box when view code button is clicked"""
850
+ index = evt.index
851
+ return gr.update(visible=True) if index < len(code_boxes) else gr.update(visible=False)
852
+
853
+ # Add click handlers for each view code button
854
+ for i, (view_btn, code_box) in enumerate(zip(view_code_buttons, code_boxes)):
855
+ view_btn.click(
856
+ fn=lambda: gr.update(visible=True),
857
+ inputs=None,
858
+ outputs=[code_box]
859
+ )
860
+
861
+ def download_svg(svg_code, index):
862
+ """Download SVG file"""
863
+ if not svg_code:
864
+ return None
865
+ temp_file = f"testimonial_{index+1}.svg"
866
+ with open(temp_file, "w", encoding="utf-8") as f:
867
+ f.write(svg_code)
868
+ return temp_file
869
+
870
+ # Add click handlers for download buttons
871
+ for i, (download_btn, file_output) in enumerate(download_buttons):
872
+ download_btn.click(
873
+ fn=lambda x, idx=i: download_svg(x, idx),
874
+ inputs=[code_boxes[i]],
875
+ outputs=[file_output]
876
+ )
877
+
878
+ # Add click handler for single SVG download
879
+ download_btn.click(
880
+ fn=lambda x: download_svg(x, 0),
881
+ inputs=[svg_code_box],
882
+ outputs=[file_output]
883
+ )
884
 
885
+ demo.launch(
886
+ server_name="127.0.0.1", # Localhost for better stability
887
+ server_port=7860, # Default Gradio port
888
+ share=True, # Creates a shareable link
889
+ show_error=True
890
+ )
891
+ logging.info("Application launched successfully")
892
+ except Exception as e:
893
+ logging.error(f"Error launching application: {str(e)}", exc_info=True)