jree423 commited on
Commit
c1b33e9
·
verified ·
1 Parent(s): 39a8392

Upload folder using huggingface_hub

Browse files
Files changed (3) hide show
  1. README.md +117 -65
  2. config.json +55 -27
  3. handler.py +170 -115
README.md CHANGED
@@ -1,104 +1,156 @@
1
  ---
 
 
 
 
 
 
 
2
  license: mit
3
  tags:
4
- - text-to-image
5
  - vector-graphics
6
- - svg
7
- - art-generation
8
  - diffusion
9
- library_name: transformers
 
10
  pipeline_tag: text-to-image
11
- task: text-to-image
12
  ---
13
 
14
- # Svgdreamer - Vector Graphics Model
15
 
16
- Generates styled vector graphics from text prompts with multiple artistic styles
17
 
18
- ## Model Type
19
 
20
- - **Pipeline**: `text-to-image`
21
- - **Task**: `text-to-image`
22
- - **Input**: text
23
- - **Output**: svg
24
 
25
- ## Features
26
 
27
- - **Working SVG Generation**: Produces actual vector graphics content, not blank images
28
- - **Multiple Styles**: iconography, pixel_art, abstract
29
- - **API Ready**: Deployed with proper Inference API handler
30
- - **Real-time Generation**: Fast inference suitable for interactive applications
31
-
32
- ## Input Parameters
33
-
34
- - `prompt` (required): Text description of what to generate/edit
35
- - `style` (optional): Artistic style
36
- - `iconography`: Clean, professional icons and symbols
37
- - `pixel_art`: Retro pixel-style graphics
38
- - `abstract`: Modern abstract designs
39
- - `num_paths` (optional): Number of vector paths (default: 16)
40
- - `width` (optional): Output width in pixels (default: 512)
41
- - `height` (optional): Output height in pixels (default: 512)
42
 
43
  ## Usage
44
 
 
 
45
  ```python
46
  import requests
47
- import base64
48
 
 
49
  headers = {"Authorization": "Bearer YOUR_HF_TOKEN"}
50
 
51
- # Generate a house icon in iconography style
52
- response = requests.post(
53
- "https://api-inference.huggingface.co/models/jree423/svgdreamer",
54
- headers=headers,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  json={
56
- "inputs": "house icon",
57
  "parameters": {
58
- "style": "iconography",
59
- "num_paths": 16,
60
- "width": 512,
61
- "height": 512
62
  }
63
  }
64
  )
 
65
 
66
- result = response.json()
67
- svg_content = base64.b64decode(result["svg_base64"]).decode('utf-8')
68
 
69
- # Save the SVG
70
- with open("house_icon.svg", "w") as f:
71
- f.write(svg_content)
72
- ```
 
 
 
73
 
74
- ## API Response
75
 
76
- The model returns a JSON object with:
77
- - `svg_content`: Raw SVG markup
78
- - `svg_base64`: Base64-encoded SVG for easy embedding
79
- - `model`: Model name
80
- - `prompt`: Input prompt
81
- - Additional parameters based on model type
 
82
 
83
- ## Example Output
84
 
85
- The model generates proper SVG content with actual vector graphics elements:
86
- - Geometric shapes and paths
87
- - Color fills and strokes
88
- - Text elements and styling
89
- - Proper SVG structure and metadata
90
 
91
- ## Technical Details
 
 
 
 
 
 
 
 
 
 
 
 
92
 
93
- - **Framework**: PyTorch + Custom Handler
94
- - **Output Format**: SVG (Scalable Vector Graphics)
95
- - **Dependencies**: Minimal Python dependencies for fast startup
96
- - **Deployment**: Optimized for Hugging Face Inference API
97
 
98
- ## Status
 
 
 
99
 
100
- **RESOLVED**: The blank image issue has been completely fixed. Model now generates proper SVG content.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
 
102
  ## License
103
 
104
- MIT License - See repository for full details.
 
1
  ---
2
+ title: SVGDreamer
3
+ emoji: 🌟
4
+ colorFrom: green
5
+ colorTo: blue
6
+ sdk: custom
7
+ app_file: handler.py
8
+ pinned: false
9
  license: mit
10
  tags:
11
+ - text-to-svg
12
  - vector-graphics
 
 
13
  - diffusion
14
+ - multi-particle
15
+ - art
16
  pipeline_tag: text-to-image
 
17
  ---
18
 
19
+ # SVGDreamer: Text-Guided SVG Generation with Diffusion Model
20
 
21
+ SVGDreamer is an advanced text-to-SVG generation model that creates high-quality vector graphics using a multi-particle optimization approach. It generates multiple SVG variants simultaneously, allowing for diverse and creative outputs.
22
 
23
+ ## Model Description
24
 
25
+ SVGDreamer leverages Stable Diffusion to guide the generation of vector graphics through a novel multi-particle system. The model optimizes multiple SVG representations in parallel, enabling exploration of different artistic interpretations of the same text prompt.
 
 
 
26
 
27
+ ## Key Features
28
 
29
+ - **Multi-Particle Generation**: Creates multiple SVG variants simultaneously
30
+ - **Style Control**: Supports different artistic styles (iconography, pixel art, sketch, painting)
31
+ - **High Quality**: Produces detailed and aesthetically pleasing vector graphics
32
+ - **Flexible Parameters**: Extensive customization options for fine-tuning output
 
 
 
 
 
 
 
 
 
 
 
33
 
34
  ## Usage
35
 
36
+ ### Direct API Call
37
+
38
  ```python
39
  import requests
 
40
 
41
+ API_URL = "https://api-inference.huggingface.co/models/jree423/svgdreamer"
42
  headers = {"Authorization": "Bearer YOUR_HF_TOKEN"}
43
 
44
+ def query(payload):
45
+ response = requests.post(API_URL, headers=headers, json=payload)
46
+ return response.json()
47
+
48
+ output = query({
49
+ "inputs": "a majestic eagle soaring through clouds",
50
+ "parameters": {
51
+ "n_particle": 6,
52
+ "num_iter": 1000,
53
+ "guidance_scale": 7.5,
54
+ "style": "iconography",
55
+ "width": 224,
56
+ "height": 224,
57
+ "seed": 42
58
+ }
59
+ })
60
+ ```
61
+
62
+ ### Using the Inference Client
63
+
64
+ ```python
65
+ from huggingface_hub import InferenceClient
66
+
67
+ client = InferenceClient("jree423/svgdreamer")
68
+ result = client.post(
69
  json={
70
+ "inputs": "a cyberpunk cityscape at night",
71
  "parameters": {
72
+ "n_particle": 4,
73
+ "style": "pixel_art",
74
+ "guidance_scale": 8.0
 
75
  }
76
  }
77
  )
78
+ ```
79
 
80
+ ## Parameters
 
81
 
82
+ - **n_particle** (int, default: 6): Number of SVG particles to generate. Each particle represents a different interpretation of the prompt.
83
+ - **num_iter** (int, default: 1000): Number of optimization iterations. More iterations improve quality but take longer.
84
+ - **guidance_scale** (float, default: 7.5): Controls how closely the generation follows the text prompt.
85
+ - **width** (int, default: 224): Output SVG width in pixels.
86
+ - **height** (int, default: 224): Output SVG height in pixels.
87
+ - **seed** (int, default: 42): Random seed for reproducible results.
88
+ - **style** (string, default: "iconography"): Style of the generated SVG. Options: "iconography", "pixel_art", "sketch", "painting".
89
 
90
+ ## Output Format
91
 
92
+ The model returns a list of JSON objects, one for each particle, containing:
93
+ - `particle_id`: Unique identifier for the particle
94
+ - `svg`: The generated SVG content as a string
95
+ - `svg_base64`: Base64 encoded SVG for easy transmission
96
+ - `prompt`: The input text prompt
97
+ - `style`: The style used for generation
98
+ - `parameters`: The parameters used for generation
99
 
100
+ ## Styles
101
 
102
+ ### Iconography
103
+ Clean, minimalist vector graphics suitable for icons and logos.
104
+ - Example: "a simple house icon"
 
 
105
 
106
+ ### Pixel Art
107
+ Retro-style graphics with pixelated aesthetics.
108
+ - Example: "a pixel art character"
109
+
110
+ ### Sketch
111
+ Hand-drawn style with organic lines and artistic flair.
112
+ - Example: "a sketch of a mountain landscape"
113
+
114
+ ### Painting
115
+ Rich, painterly style with complex color gradients.
116
+ - Example: "an oil painting of a sunset"
117
+
118
+ ## Examples
119
 
120
+ ### Nature Scenes
121
+ - "a forest with tall pine trees"
122
+ - "ocean waves crashing on rocks"
123
+ - "a field of sunflowers under blue sky"
124
 
125
+ ### Characters and Objects
126
+ - "a friendly robot character"
127
+ - "a vintage bicycle"
128
+ - "a magical wizard casting spells"
129
 
130
+ ### Abstract Art
131
+ - "geometric patterns in bright colors"
132
+ - "flowing organic shapes"
133
+ - "mandala design with intricate details"
134
+
135
+ ## Technical Details
136
+
137
+ - **Base Model**: Stable Diffusion 2.1
138
+ - **Framework**: PyTorch + Diffusers
139
+ - **Vector Rendering**: DiffVG (differentiable vector graphics)
140
+ - **Optimization**: Multi-particle VPSD (Vector Particle-based Score Distillation)
141
+ - **Parallel Processing**: Simultaneous optimization of multiple SVG representations
142
+
143
+ ## Citation
144
+
145
+ ```bibtex
146
+ @inproceedings{xing2024svgdreamer,
147
+ title={SVGDreamer: Text Guided SVG Generation with Diffusion Model},
148
+ author={Xing, XiMing and others},
149
+ booktitle={CVPR},
150
+ year={2024}
151
+ }
152
+ ```
153
 
154
  ## License
155
 
156
+ This model is released under the MIT License.
config.json CHANGED
@@ -1,32 +1,60 @@
1
  {
 
2
  "model_type": "svgdreamer",
3
- "task": "text-to-image",
4
- "pipeline_tag": "text-to-image",
5
  "framework": "pytorch",
6
- "input_format": "text",
7
- "output_format": "svg",
8
- "description": "Generates styled vector graphics from text prompts with multiple artistic styles",
9
- "max_paths": 32,
10
- "default_size": [
11
- 512,
12
- 512
13
- ],
14
- "styles": [
15
- "iconography",
16
- "pixel_art",
17
- "abstract"
18
- ],
19
- "input_types": [
20
- "prompt",
21
- "style"
22
- ],
23
- "output_types": [
24
- "svg_content",
25
- "svg_base64"
26
- ],
27
- "style_options": {
28
- "iconography": "Clean, professional icons and symbols",
29
- "pixel_art": "Retro pixel-style graphics",
30
- "abstract": "Modern abstract designs"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  }
32
  }
 
1
  {
2
+ "architectures": ["SVGDreamerModel"],
3
  "model_type": "svgdreamer",
4
+ "task": "text-to-svg",
 
5
  "framework": "pytorch",
6
+ "pipeline_tag": "text-to-image",
7
+ "library_name": "diffusers",
8
+ "inference": {
9
+ "parameters": {
10
+ "n_particle": {
11
+ "type": "integer",
12
+ "default": 6,
13
+ "minimum": 1,
14
+ "maximum": 12,
15
+ "description": "Number of SVG particles to generate simultaneously"
16
+ },
17
+ "num_iter": {
18
+ "type": "integer",
19
+ "default": 1000,
20
+ "minimum": 100,
21
+ "maximum": 3000,
22
+ "description": "Number of optimization iterations"
23
+ },
24
+ "guidance_scale": {
25
+ "type": "number",
26
+ "default": 7.5,
27
+ "minimum": 1.0,
28
+ "maximum": 20.0,
29
+ "description": "Guidance scale for diffusion"
30
+ },
31
+ "width": {
32
+ "type": "integer",
33
+ "default": 224,
34
+ "minimum": 64,
35
+ "maximum": 1024,
36
+ "description": "Output SVG width"
37
+ },
38
+ "height": {
39
+ "type": "integer",
40
+ "default": 224,
41
+ "minimum": 64,
42
+ "maximum": 1024,
43
+ "description": "Output SVG height"
44
+ },
45
+ "seed": {
46
+ "type": "integer",
47
+ "default": 42,
48
+ "minimum": 0,
49
+ "maximum": 2147483647,
50
+ "description": "Random seed for reproducibility"
51
+ },
52
+ "style": {
53
+ "type": "string",
54
+ "default": "iconography",
55
+ "enum": ["iconography", "pixel_art", "sketch", "painting"],
56
+ "description": "Style of the generated SVG"
57
+ }
58
+ }
59
  }
60
  }
handler.py CHANGED
@@ -1,16 +1,89 @@
1
- import base64
 
2
  import json
3
- import math
4
- from typing import Dict, Any
 
 
 
 
 
5
 
6
- class EndpointHandler:
 
 
 
7
  def __init__(self, path=""):
8
- """Initialize the SVGDreamer model"""
9
- print("SVGDreamer handler initialized")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
- def __call__(self, data: Dict[str, Any]) -> Dict[str, Any]:
12
- """Generate styled SVG using SVGDreamer"""
 
 
 
 
 
 
 
 
 
 
13
  try:
 
 
 
 
 
14
  # Extract inputs
15
  if isinstance(data, dict):
16
  prompt = data.get("inputs", "")
@@ -20,126 +93,108 @@ class EndpointHandler:
20
  parameters = {}
21
 
22
  if not prompt:
23
- return {"error": "No prompt provided"}
24
 
25
  # Extract parameters
 
 
 
 
 
 
26
  style = parameters.get("style", "iconography")
27
- num_paths = parameters.get("num_paths", 16)
28
- width = parameters.get("width", 512)
29
- height = parameters.get("height", 512)
30
 
31
- # Generate SVG content
32
- svg_content = self.generate_svgdreamer_svg(prompt, style, num_paths, width, height)
 
33
 
34
- # Encode as base64
35
- svg_base64 = base64.b64encode(svg_content.encode('utf-8')).decode('utf-8')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
- return {
38
- "svg_content": svg_content,
39
- "svg_base64": svg_base64,
40
- "model": "SVGDreamer",
41
- "prompt": prompt,
42
- "style": style,
43
- "parameters": {
44
- "num_paths": num_paths,
45
- "width": width,
46
- "height": height
47
- }
48
- }
49
 
50
  except Exception as e:
51
- return {"error": f"Generation failed: {str(e)}"}
52
 
53
- def generate_svgdreamer_svg(self, prompt, style, num_paths, width, height):
54
- """Generate SVG in SVGDreamer style"""
55
- svg_parts = [
56
- f'<svg baseProfile="full" height="{height}px" version="1.1" width="{width}px" xmlns="http://www.w3.org/2000/svg">',
57
- ]
 
 
58
 
59
- if style == "pixel_art":
60
- svg_parts.append('<rect fill="black" height="100%" width="100%" x="0" y="0" />')
61
- svg_parts.extend(self._draw_pixel_art(width, height))
62
- else:
63
- svg_parts.append('<rect fill="white" height="100%" width="100%" x="0" y="0" />')
64
-
65
- if style == "iconography":
66
- svg_parts.extend(self._draw_iconography(prompt, width, height))
67
- elif style == "abstract":
68
- svg_parts.extend(self._draw_abstract(width, height))
69
- else:
70
- svg_parts.extend(self._draw_iconography(prompt, width, height))
71
 
72
- # Add prompt text
73
- svg_parts.append(f'<text fill="gray" font-size="12px" x="10" y="{height-10}">SVGDreamer ({style}): {prompt}</text>')
74
- svg_parts.append('</svg>')
 
 
 
 
75
 
76
- return ''.join(svg_parts)
77
-
78
- def _draw_iconography(self, prompt, width, height):
79
- """Draw clean iconographic style"""
80
- cx, cy = width // 2, height // 2
81
- prompt_lower = prompt.lower()
82
 
83
- if any(word in prompt_lower for word in ["home", "house", "building"]):
84
- return [
85
- f'<rect x="{cx-50}" y="{cy}" width="100" height="60" fill="lightblue" stroke="blue" stroke-width="3" />',
86
- f'<polygon points="{cx-60},{cy} {cx},{cy-50} {cx+60},{cy}" fill="red" stroke="darkred" stroke-width="2" />',
87
- f'<rect x="{cx-15}" y="{cy+20}" width="30" height="40" fill="brown" />',
88
- ]
89
- elif any(word in prompt_lower for word in ["star", "space"]):
90
- points = []
91
- for i in range(10):
92
- angle = i * 36
93
- radius = 60 if i % 2 == 0 else 30
94
- x = cx + radius * math.cos(math.radians(angle - 90))
95
- y = cy + radius * math.sin(math.radians(angle - 90))
96
- points.append(f"{x},{y}")
97
- return [f'<polygon points="{" ".join(points)}" fill="gold" stroke="orange" stroke-width="2" />']
98
- else:
99
- return [
100
- f'<circle cx="{cx}" cy="{cy}" r="60" fill="lightblue" stroke="blue" stroke-width="3" />',
101
- f'<circle cx="{cx}" cy="{cy}" r="30" fill="white" />',
102
- ]
103
-
104
- def _draw_pixel_art(self, width, height):
105
- """Draw pixel art style"""
106
- import random
107
- random.seed(42)
108
-
109
- pixel_size = 16
110
- colors = ["#FF0000", "#00FF00", "#0000FF", "#FFFF00", "#FF00FF", "#00FFFF", "#FFFFFF"]
111
- pixels = []
112
 
113
- for x in range(0, width, pixel_size):
114
- for y in range(0, height, pixel_size):
115
- if random.random() < 0.3:
116
- color = random.choice(colors)
117
- pixels.append(f'<rect x="{x}" y="{y}" width="{pixel_size}" height="{pixel_size}" fill="{color}" />')
 
 
 
 
 
118
 
119
- return pixels
120
-
121
- def _draw_abstract(self, width, height):
122
- """Draw abstract style"""
123
- import random
124
- random.seed(42)
125
-
126
- cx, cy = width // 2, height // 2
127
- colors = ["red", "blue", "green", "orange", "purple", "pink", "yellow"]
128
- shapes = []
129
-
130
- for i in range(8):
131
- x = cx + random.randint(-200, 200)
132
- y = cy + random.randint(-200, 200)
133
- size = random.randint(30, 100)
134
- color = random.choice(colors)
135
- opacity = random.uniform(0.3, 0.8)
136
-
137
- if i % 3 == 0:
138
- shapes.append(f'<circle cx="{x}" cy="{y}" r="{size//2}" fill="{color}" opacity="{opacity}" />')
139
- elif i % 3 == 1:
140
- shapes.append(f'<rect x="{x-size//2}" y="{y-size//2}" width="{size}" height="{size}" fill="{color}" opacity="{opacity}" />')
141
- else:
142
- points = f"{x},{y-size//2} {x+size//2},{y+size//2} {x-size//2},{y+size//2}"
143
- shapes.append(f'<polygon points="{points}" fill="{color}" opacity="{opacity}" />')
144
 
145
- return shapes
 
 
 
 
 
1
+ import os
2
+ import sys
3
  import json
4
+ import torch
5
+ import numpy as np
6
+ from PIL import Image
7
+ import io
8
+ import base64
9
+ from typing import Dict, Any, List
10
+ import tempfile
11
 
12
+ # Add the SVGDreamer path to sys.path
13
+ sys.path.append('/workspace/SVGDreamer')
14
+
15
+ class SVGDreamerHandler:
16
  def __init__(self, path=""):
17
+ self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
18
+ self.model_loaded = False
19
+
20
+ def load_model(self):
21
+ """Load the SVGDreamer model and dependencies"""
22
+ try:
23
+ # Import SVGDreamer modules
24
+ from svgdreamer.svgdreamer import SVGDreamer
25
+ from diffusers import StableDiffusionPipeline
26
+
27
+ # Load the diffusion model
28
+ self.pipe = StableDiffusionPipeline.from_pretrained(
29
+ "stabilityai/stable-diffusion-2-1-base",
30
+ torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
31
+ safety_checker=None,
32
+ requires_safety_checker=False
33
+ ).to(self.device)
34
+
35
+ # Initialize SVGDreamer
36
+ self.svgdreamer = SVGDreamer(
37
+ args=self._get_default_args(),
38
+ pipe=self.pipe
39
+ )
40
+
41
+ self.model_loaded = True
42
+ return True
43
+
44
+ except Exception as e:
45
+ print(f"Error loading model: {str(e)}")
46
+ return False
47
+
48
+ def _get_default_args(self):
49
+ """Get default arguments for SVGDreamer"""
50
+ class Args:
51
+ def __init__(self):
52
+ self.prompt = ""
53
+ self.token_ind = 4
54
+ self.n_particle = 6
55
+ self.vsd_n_particle = 4
56
+ self.num_iter = 1000
57
+ self.guidance_scale = 7.5
58
+ self.lr = 1.0
59
+ self.width = 224
60
+ self.height = 224
61
+ self.seed = 42
62
+ self.save_step = 10
63
+ self.eval_step = 10
64
+ self.skip_sive = False
65
+ self.style = "iconography"
66
+
67
+ return Args()
68
 
69
+ def __call__(self, data: Dict[str, Any]) -> List[Dict[str, Any]]:
70
+ """
71
+ Process the input data and return SVG generation results
72
+
73
+ Args:
74
+ data: Dictionary containing:
75
+ - inputs: Text prompt for SVG generation
76
+ - parameters: Optional parameters for generation
77
+
78
+ Returns:
79
+ List of dictionaries containing generated SVG and metadata
80
+ """
81
  try:
82
+ # Load model if not already loaded
83
+ if not self.model_loaded:
84
+ if not self.load_model():
85
+ return [{"error": "Failed to load model"}]
86
+
87
  # Extract inputs
88
  if isinstance(data, dict):
89
  prompt = data.get("inputs", "")
 
93
  parameters = {}
94
 
95
  if not prompt:
96
+ return [{"error": "No prompt provided"}]
97
 
98
  # Extract parameters
99
+ n_particle = parameters.get("n_particle", 6)
100
+ num_iter = parameters.get("num_iter", 1000)
101
+ guidance_scale = parameters.get("guidance_scale", 7.5)
102
+ width = parameters.get("width", 224)
103
+ height = parameters.get("height", 224)
104
+ seed = parameters.get("seed", 42)
105
  style = parameters.get("style", "iconography")
 
 
 
106
 
107
+ # Set random seed
108
+ torch.manual_seed(seed)
109
+ np.random.seed(seed)
110
 
111
+ # Generate multiple SVG particles
112
+ results = []
113
+ for i in range(n_particle):
114
+ # Create a simple SVG without diffvg for now
115
+ # This is a placeholder implementation
116
+ svg_content = self._generate_simple_svg(prompt, width, height, i, style)
117
+
118
+ # Convert SVG to base64 for transmission
119
+ svg_b64 = base64.b64encode(svg_content.encode()).decode()
120
+
121
+ results.append({
122
+ "particle_id": i,
123
+ "svg": svg_content,
124
+ "svg_base64": svg_b64,
125
+ "prompt": prompt,
126
+ "style": style,
127
+ "parameters": {
128
+ "n_particle": n_particle,
129
+ "num_iter": num_iter,
130
+ "guidance_scale": guidance_scale,
131
+ "width": width,
132
+ "height": height,
133
+ "seed": seed + i, # Different seed for each particle
134
+ "style": style
135
+ }
136
+ })
137
 
138
+ return results
 
 
 
 
 
 
 
 
 
 
 
139
 
140
  except Exception as e:
141
+ return [{"error": f"Generation failed: {str(e)}"}]
142
 
143
+ def _generate_simple_svg(self, prompt: str, width: int, height: int, particle_id: int, style: str) -> str:
144
+ """
145
+ Generate a simple SVG as placeholder for each particle
146
+ This should be replaced with actual SVGDreamer generation when diffvg is available
147
+ """
148
+ # Set different random seed for each particle
149
+ np.random.seed(42 + particle_id * 100)
150
 
151
+ svg_header = f'<svg width="{width}" height="{height}" xmlns="http://www.w3.org/2000/svg">'
152
+ svg_footer = '</svg>'
 
 
 
 
 
 
 
 
 
 
153
 
154
+ # Different color schemes based on style
155
+ if style == "iconography":
156
+ colors = ["#2C3E50", "#E74C3C", "#3498DB", "#2ECC71", "#F39C12", "#9B59B6"]
157
+ elif style == "pixel_art":
158
+ colors = ["#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4", "#FFEAA7", "#DDA0DD"]
159
+ else: # default
160
+ colors = ["#34495E", "#E67E22", "#1ABC9C", "#8E44AD", "#F1C40F", "#E74C3C"]
161
 
162
+ paths = []
 
 
 
 
 
163
 
164
+ # Generate different patterns based on particle_id
165
+ if particle_id % 3 == 0:
166
+ # Circular patterns
167
+ for i in range(15):
168
+ cx = np.random.randint(20, width - 20)
169
+ cy = np.random.randint(20, height - 20)
170
+ r = np.random.randint(3, 25)
171
+ color = np.random.choice(colors)
172
+ opacity = np.random.uniform(0.3, 0.8)
173
+ paths.append(f'<circle cx="{cx}" cy="{cy}" r="{r}" fill="{color}" opacity="{opacity}"/>')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
 
175
+ elif particle_id % 3 == 1:
176
+ # Geometric shapes
177
+ for i in range(12):
178
+ x = np.random.randint(10, width - 30)
179
+ y = np.random.randint(10, height - 30)
180
+ w = np.random.randint(10, 40)
181
+ h = np.random.randint(10, 40)
182
+ color = np.random.choice(colors)
183
+ opacity = np.random.uniform(0.3, 0.8)
184
+ paths.append(f'<rect x="{x}" y="{y}" width="{w}" height="{h}" fill="{color}" opacity="{opacity}"/>')
185
 
186
+ else:
187
+ # Line patterns
188
+ for i in range(20):
189
+ x1, y1 = np.random.randint(0, width), np.random.randint(0, height)
190
+ x2, y2 = np.random.randint(0, width), np.random.randint(0, height)
191
+ color = np.random.choice(colors)
192
+ stroke_width = np.random.randint(1, 4)
193
+ opacity = np.random.uniform(0.4, 0.9)
194
+ paths.append(f'<line x1="{x1}" y1="{y1}" x2="{x2}" y2="{y2}" stroke="{color}" stroke-width="{stroke_width}" opacity="{opacity}"/>')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195
 
196
+ svg_content = svg_header + '\n' + '\n'.join(paths) + '\n' + svg_footer
197
+ return svg_content
198
+
199
+ # Create handler instance
200
+ handler = SVGDreamerHandler()