sidharthg commited on
Commit
1c70275
Β·
verified Β·
1 Parent(s): f385651

Upload 5 files

Browse files
Files changed (5) hide show
  1. DEPLOYMENT_GUIDE.md +139 -0
  2. QUICKSTART.md +83 -0
  3. README.md +78 -13
  4. app.py +503 -0
  5. requirements.txt +9 -0
DEPLOYMENT_GUIDE.md ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Hugging Face Spaces Deployment Guide
2
+
3
+ ## Quick Start - Deploy to Hugging Face Spaces
4
+
5
+ ### Option 1: Web Upload (Easiest)
6
+
7
+ 1. **Create a New Space**
8
+ - Go to https://huggingface.co/new-space
9
+ - Name your space (e.g., "stable-diffusion-style-explorer")
10
+ - Select **Gradio** as the SDK
11
+ - Choose your preferred visibility (Public/Private)
12
+ - Click "Create Space"
13
+
14
+ 2. **Upload Files**
15
+ - Click "Files" tab in your new Space
16
+ - Click "Add file" β†’ "Upload files"
17
+ - Upload these files from `hf_app/` folder:
18
+ - `app.py`
19
+ - `requirements.txt`
20
+ - `README.md`
21
+ - Click "Commit changes to main"
22
+
23
+ 3. **Wait for Build**
24
+ - The Space will automatically build (takes 5-10 minutes first time)
25
+ - You'll see build logs in the "Logs" tab
26
+ - Once complete, your app will be live!
27
+
28
+ ### Option 2: Git Push (Advanced)
29
+
30
+ ```bash
31
+ # Navigate to the hf_app directory
32
+ cd C:\Users\sidhe\TSAIV4\Session15-Assignment\hf_app
33
+
34
+ # Initialize git (if not already done)
35
+ git init
36
+
37
+ # Add Hugging Face Space as remote
38
+ # Replace YOUR_USERNAME and YOUR_SPACE_NAME
39
+ git remote add origin https://huggingface.co/spaces/YOUR_USERNAME/YOUR_SPACE_NAME
40
+
41
+ # Add and commit files
42
+ git add .
43
+ git commit -m "Initial commit: Stable Diffusion Style Explorer"
44
+
45
+ # Push to Hugging Face
46
+ git push origin main
47
+ ```
48
+
49
+ ## Local Testing (Optional)
50
+
51
+ Test the app locally before deploying:
52
+
53
+ ```bash
54
+ # Navigate to hf_app directory
55
+ cd C:\Users\sidhe\TSAIV4\Session15-Assignment\hf_app
56
+
57
+ # Install dependencies
58
+ pip install -r requirements.txt
59
+
60
+ # Run the app
61
+ python app.py
62
+ ```
63
+
64
+ The app will open at `http://localhost:7860`
65
+
66
+ ## Hardware Requirements
67
+
68
+ ### For Hugging Face Spaces:
69
+ - **Free Tier (CPU)**: Works but slow (~2-3 minutes per image)
70
+ - **Upgraded (GPU)**: Recommended for production
71
+ - T4 GPU: ~10-15 seconds per image
72
+ - A10G GPU: ~5-8 seconds per image
73
+
74
+ ### To Upgrade Space Hardware:
75
+ 1. Go to your Space settings
76
+ 2. Click "Hardware" tab
77
+ 3. Select GPU tier (requires payment)
78
+
79
+ ## Troubleshooting
80
+
81
+ ### Build Fails
82
+ - Check `requirements.txt` versions are compatible
83
+ - Review build logs in Spaces "Logs" tab
84
+ - Ensure all imports in `app.py` are in `requirements.txt`
85
+
86
+ ### Out of Memory
87
+ - Reduce `num_inference_steps` default value
88
+ - Use CPU instead of GPU (slower but more memory)
89
+ - Upgrade to larger GPU tier
90
+
91
+ ### Slow Generation
92
+ - Upgrade to GPU hardware
93
+ - Reduce inference steps (trade quality for speed)
94
+ - Consider caching the pipeline
95
+
96
+ ## Customization
97
+
98
+ ### Add More Styles
99
+ Edit `app.py` and add to the `STYLES` dictionary:
100
+
101
+ ```python
102
+ STYLES = {
103
+ # ... existing styles ...
104
+ "Your Style Name": {
105
+ "repo": "sd-concepts-library/your-concept",
106
+ "token": "<your-token>",
107
+ "description": "Your style description"
108
+ }
109
+ }
110
+ ```
111
+
112
+ ### Change Base Model
113
+ Replace in `app.py`:
114
+ ```python
115
+ pipe = StableDiffusionPipeline.from_pretrained(
116
+ "runwayml/stable-diffusion-v1-5", # or another model
117
+ torch_dtype=dtype,
118
+ safety_checker=None
119
+ ).to(device)
120
+ ```
121
+
122
+ ### Adjust Default Parameters
123
+ Modify the default values in the Gradio components:
124
+ - `steps_single = gr.Slider(..., value=30, ...)` - Change default steps
125
+ - `guidance_single = gr.Slider(..., value=7.5, ...)` - Change guidance scale
126
+
127
+ ## Next Steps
128
+
129
+ 1. βœ… Deploy to Hugging Face Spaces
130
+ 2. βœ… Test with different prompts and styles
131
+ 3. βœ… Share your Space URL with others
132
+ 4. βœ… Monitor usage in Space analytics
133
+ 5. βœ… Iterate based on user feedback
134
+
135
+ ## Support
136
+
137
+ - Hugging Face Spaces Docs: https://huggingface.co/docs/hub/spaces
138
+ - Gradio Documentation: https://gradio.app/docs
139
+ - Diffusers Documentation: https://huggingface.co/docs/diffusers
QUICKSTART.md ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Quick Start Guide - Local Testing
2
+
3
+ ## Installation Complete! βœ…
4
+
5
+ All dependencies have been installed successfully. Here's what to do next:
6
+
7
+ ## Running the App
8
+
9
+ ### Option 1: Simple Run
10
+ ```bash
11
+ python app.py
12
+ ```
13
+
14
+ The app will start and show you a URL like:
15
+ ```
16
+ Running on local URL: http://127.0.0.1:7860
17
+ ```
18
+
19
+ Open that URL in your browser!
20
+
21
+ ### Option 2: Share Publicly (Temporary)
22
+ ```bash
23
+ # Edit app.py, change the last line to:
24
+ demo.launch(share=True)
25
+ ```
26
+
27
+ This creates a temporary public URL you can share with others.
28
+
29
+ ## What to Expect
30
+
31
+ ### First Run
32
+ - The app will download the Stable Diffusion model (~4GB)
33
+ - This happens only once - subsequent runs are fast
34
+ - Download location: `~/.cache/huggingface/`
35
+
36
+ ### Performance
37
+ - **With GPU (CUDA)**: ~10-15 seconds per image
38
+ - **Without GPU (CPU)**: ~2-3 minutes per image
39
+
40
+ Check if CUDA is available:
41
+ ```bash
42
+ python -c "import torch; print(f'CUDA available: {torch.cuda.is_available()}')"
43
+ ```
44
+
45
+ ## Using the App
46
+
47
+ ### Single Style Tab
48
+ 1. Enter a prompt (use `<style>` as placeholder)
49
+ - Example: `"a portrait of a warrior in <style>"`
50
+ 2. Select a style from dropdown
51
+ 3. Set seed (e.g., 42)
52
+ 4. Click "Generate Image"
53
+
54
+ ### Compare All Styles Tab
55
+ 1. Enter a prompt with `<style>` placeholder
56
+ 2. Set base seed (e.g., 100)
57
+ 3. Click "Generate All Styles"
58
+ 4. See all 5 styles side-by-side!
59
+
60
+ ## Troubleshooting
61
+
62
+ ### "Out of Memory" Error
63
+ - Reduce inference steps to 20-30
64
+ - Close other GPU applications
65
+ - Use CPU mode (slower but works)
66
+
67
+ ### Slow Generation
68
+ - This is normal on CPU
69
+ - Consider using GPU for faster results
70
+ - Reduce inference steps for speed
71
+
72
+ ### Model Download Fails
73
+ - Check internet connection
74
+ - Ensure ~5GB free disk space
75
+ - Try again - downloads resume automatically
76
+
77
+ ## Next Steps
78
+
79
+ 1. βœ… Test the app locally
80
+ 2. βœ… Try different prompts and styles
81
+ 3. βœ… Deploy to Hugging Face Spaces (see DEPLOYMENT_GUIDE.md)
82
+
83
+ Enjoy your Stable Diffusion Style Explorer! 🎨
README.md CHANGED
@@ -1,13 +1,78 @@
1
- ---
2
- title: SDConcepts
3
- emoji: πŸ†
4
- colorFrom: blue
5
- colorTo: yellow
6
- sdk: gradio
7
- sdk_version: 6.2.0
8
- app_file: app.py
9
- pinned: false
10
- short_description: An interactive web application for exploring different style
11
- ---
12
-
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Stable Diffusion Style Explorer
3
+ emoji: 🎨
4
+ colorFrom: purple
5
+ colorTo: pink
6
+ sdk: gradio
7
+ sdk_version: 4.44.0
8
+ app_file: app.py
9
+ pinned: false
10
+ license: mit
11
+ ---
12
+
13
+ # Stable Diffusion Style Explorer
14
+
15
+ An interactive web application for exploring different artistic styles using Stable Diffusion with textual inversion.
16
+
17
+ ## Features
18
+
19
+ - **5 Pre-configured Styles**: Cat Toy, GTA5 Artwork, Birb Style, Midjourney Style, and Arcane Style
20
+ - **Single Style Mode**: Generate images with a specific style, custom seed, and parameters
21
+ - **Compare All Styles**: Generate the same prompt across all 5 styles simultaneously
22
+ - **Seed Control**: Full control over random seeds for reproducible results
23
+ - **Adjustable Parameters**: Configure inference steps and guidance scale
24
+
25
+ ## Usage
26
+
27
+ ### Single Style Mode
28
+ 1. Enter your prompt (use `<style>` as a placeholder for the style token)
29
+ 2. Select a style from the dropdown
30
+ 3. Set your desired seed value
31
+ 4. Adjust inference steps and guidance scale if needed
32
+ 5. Click "Generate Image"
33
+
34
+ ### Compare All Styles Mode
35
+ 1. Enter your prompt (use `<style>` as a placeholder)
36
+ 2. Set a base seed value
37
+ 3. Each style will use: `base_seed + (style_index * 100)`
38
+ 4. Click "Generate All Styles" to see all variations
39
+
40
+ ## Styles
41
+
42
+ - **Cat Toy**: Cute cat toy aesthetic
43
+ - **GTA5 Artwork**: GTA V game art style
44
+ - **Birb Style**: Artistic bird illustration style
45
+ - **Midjourney Style**: Midjourney AI art aesthetic
46
+ - **Arcane Style**: Arcane Netflix series art style
47
+
48
+ ## Technical Details
49
+
50
+ - **Base Model**: CompVis/stable-diffusion-v1-4
51
+ - **Textual Inversion**: Concepts from [SD Concepts Library](https://huggingface.co/sd-concepts-library)
52
+ - **Framework**: Gradio + Diffusers
53
+ - **GPU**: Recommended for faster generation
54
+
55
+ ## Local Development
56
+
57
+ ```bash
58
+ # Clone the repository
59
+ git clone <your-repo-url>
60
+ cd <repo-name>
61
+
62
+ # Install dependencies
63
+ pip install -r requirements.txt
64
+
65
+ # Run the app
66
+ python app.py
67
+ ```
68
+
69
+ ## Deployment to Hugging Face Spaces
70
+
71
+ 1. Create a new Space on Hugging Face
72
+ 2. Select "Gradio" as the SDK
73
+ 3. Upload `app.py`, `requirements.txt`, and `README.md`
74
+ 4. The app will automatically build and deploy
75
+
76
+ ## License
77
+
78
+ MIT License - Feel free to use and modify!
app.py ADDED
@@ -0,0 +1,503 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import torch
3
+ from diffusers import StableDiffusionPipeline
4
+ import os
5
+
6
+ # Monkeypatch fixes for environment compatibility
7
+ def apply_patches():
8
+ """Apply necessary patches for tqdm and symlinks"""
9
+ import sys
10
+ import shutil
11
+
12
+ # 1. Fix tqdm Jupyter/Thread Error
13
+ try:
14
+ import tqdm
15
+ if not hasattr(tqdm, '_is_patched'):
16
+ import tqdm.notebook
17
+ import tqdm.std
18
+ tqdm.notebook.tqdm = tqdm.std.tqdm
19
+ tqdm.notebook.trange = tqdm.std.trange
20
+ if 'tqdm.auto' in sys.modules:
21
+ sys.modules['tqdm.auto'].tqdm = tqdm.std.tqdm
22
+ sys.modules['tqdm.auto'].trange = tqdm.std.trange
23
+ tqdm._is_patched = True
24
+ except ImportError:
25
+ pass
26
+
27
+ # 2. Fix Windows Symlink Permissions
28
+ try:
29
+ from huggingface_hub import file_download
30
+ if not hasattr(file_download, '_original_create_symlink'):
31
+ file_download._original_create_symlink = file_download._create_symlink
32
+
33
+ def patched_create_symlink(src, dst, new_blob=False):
34
+ try:
35
+ file_download._original_create_symlink(src, dst, new_blob)
36
+ except OSError as e:
37
+ if getattr(e, 'winerror', 0) == 1314:
38
+ if os.path.isdir(src):
39
+ shutil.copytree(src, dst)
40
+ else:
41
+ shutil.copy2(src, dst)
42
+ else:
43
+ raise
44
+
45
+ file_download._create_symlink = patched_create_symlink
46
+ except ImportError:
47
+ pass
48
+
49
+ # Apply patches before loading models
50
+ apply_patches()
51
+
52
+ # Style configurations with default seeds
53
+ STYLES = {
54
+ "Cat Toy": {
55
+ "repo": "sd-concepts-library/cat-toy",
56
+ "token": "<cat-toy>",
57
+ "description": "Cute cat toy aesthetic",
58
+ "default_seed": 42
59
+ },
60
+ "Seletti": {
61
+ "repo": "sd-concepts-library/seletti",
62
+ "token": "<seletti>",
63
+ "description": "Seletti design style",
64
+ "default_seed": 142
65
+ },
66
+ "Madhubani Art": {
67
+ "repo": "sd-concepts-library/madhubani-art",
68
+ "token": "<madhubani-art>",
69
+ "description": "Traditional Indian Madhubani art style",
70
+ "default_seed": 242
71
+ },
72
+ "Chucky": {
73
+ "repo": "sd-concepts-library/chucky",
74
+ "token": "<chucky>",
75
+ "description": "Chucky horror character style",
76
+ "default_seed": 342
77
+ },
78
+ "Indian Watercolor Portraits": {
79
+ "repo": "sd-concepts-library/indian-watercolor-portraits",
80
+ "token": "<indian-watercolor-portraits>",
81
+ "description": "Indian watercolor portrait art style",
82
+ "default_seed": 442
83
+ },
84
+ "Anime Boy": {
85
+ "repo": "sd-concepts-library/anime-boy",
86
+ "token": "<anime-boy>",
87
+ "description": "Anime boy character style",
88
+ "default_seed": 542
89
+ }
90
+ }
91
+
92
+ # Global pipeline variable
93
+ pipe = None
94
+ current_style = None
95
+
96
+ def contrast_loss(images):
97
+ """Calculate High-Contrast loss (maximizes variance/extremes)"""
98
+ return -torch.mean((images - 0.5) ** 2)
99
+
100
+ def complexity_loss(images):
101
+ """Calculate Complexity loss (maximizes local detail/edges)"""
102
+ diff_h = torch.abs(images[:, :, 1:, :] - images[:, :, :-1, :])
103
+ diff_v = torch.abs(images[:, :, :, 1:] - images[:, :, :, :-1])
104
+ return torch.mean(diff_h) + torch.mean(diff_v)
105
+
106
+ def vibrancy_loss(images):
107
+ """Calculate Vibrancy loss (maximizes color saturation/variety)"""
108
+ # Maximize standard deviation across color channels
109
+ # Or boost the distance from grayscale
110
+ means = torch.mean(images, dim=1, keepdim=True)
111
+ return -torch.mean((images - means) ** 2)
112
+
113
+ def custom_sampling_loop(prompt, pipe, guidance_scale=7.5, contrast_scale=0.0, complexity_scale=0.0, vibrancy_scale=0.0, num_inference_steps=50, generator=None, num_images=1):
114
+ device = pipe.device
115
+ dtype = pipe.unet.dtype
116
+ text_input = pipe.tokenizer([prompt] * num_images, padding="max_length", max_length=pipe.tokenizer.model_max_length, truncation=True, return_tensors="pt")
117
+ text_embeddings = pipe.text_encoder(text_input.input_ids.to(device))[0]
118
+ uncond_input = pipe.tokenizer([""] * num_images, padding="max_length", max_length=text_input.input_ids.shape[-1], return_tensors="pt")
119
+ uncond_embeddings = pipe.text_encoder(uncond_input.input_ids.to(device))[0]
120
+ text_embeddings = torch.cat([uncond_embeddings, text_embeddings])
121
+ latents = torch.randn((num_images, pipe.unet.config.in_channels, 512 // 8, 512 // 8), generator=generator, device=device, dtype=dtype)
122
+ pipe.scheduler.set_timesteps(num_inference_steps)
123
+ latents = latents * pipe.scheduler.init_noise_sigma
124
+ import tqdm
125
+ for t in tqdm.auto.tqdm(pipe.scheduler.timesteps):
126
+ latent_model_input = torch.cat([latents] * 2)
127
+ latent_model_input = pipe.scheduler.scale_model_input(latent_model_input, t)
128
+ with torch.no_grad():
129
+ noise_pred = pipe.unet(latent_model_input, t, encoder_hidden_states=text_embeddings).sample
130
+ noise_pred_uncond, noise_pred_text = noise_pred.chunk(2)
131
+ noise_pred = noise_pred_uncond + guidance_scale * (noise_pred_text - noise_pred_uncond)
132
+
133
+ # COMBINED GUIDANCE GRADIENT STEP
134
+ if contrast_scale > 0 or complexity_scale > 0 or vibrancy_scale > 0:
135
+ latents = latents.detach().requires_grad_(True)
136
+ image = pipe.vae.decode(1 / 0.18215 * latents).sample
137
+ image = (image / 2 + 0.5).clamp(0, 1)
138
+
139
+ loss = 0
140
+ if contrast_scale > 0:
141
+ loss = loss + contrast_loss(image) * contrast_scale
142
+ if complexity_scale > 0:
143
+ loss = loss - complexity_loss(image) * complexity_scale
144
+ if vibrancy_scale > 0:
145
+ loss = loss + vibrancy_loss(image) * vibrancy_scale
146
+
147
+ cond_grad = torch.autograd.grad(loss, latents)[0]
148
+ latents = latents.detach() - cond_grad
149
+
150
+ latents = pipe.scheduler.step(noise_pred, t, latents).prev_sample
151
+ with torch.no_grad():
152
+ image = pipe.vae.decode(1 / 0.18215 * latents).sample
153
+ image = (image / 2 + 0.5).clamp(0, 1)
154
+ image = image.cpu().permute(0, 2, 3, 1).numpy()
155
+ return pipe.numpy_to_pil(image)
156
+
157
+ def initialize_pipeline():
158
+ """Initialize the Stable Diffusion pipeline"""
159
+ global pipe
160
+
161
+ if pipe is None:
162
+ print("Loading Stable Diffusion pipeline...")
163
+ device = "cuda" if torch.cuda.is_available() else "cpu"
164
+ dtype = torch.float16 if device == "cuda" else torch.float32
165
+
166
+ pipe = StableDiffusionPipeline.from_pretrained(
167
+ "CompVis/stable-diffusion-v1-4",
168
+ torch_dtype=dtype,
169
+ use_safetensors=True,
170
+ safety_checker=None
171
+ ).to(device)
172
+
173
+ # Performance optimizations
174
+ if device == "cuda":
175
+ pipe.enable_attention_slicing()
176
+ # Try to use xformers if available
177
+ try:
178
+ pipe.enable_xformers_memory_efficient_attention()
179
+ print("xformers enabled")
180
+ except Exception:
181
+ pass
182
+
183
+ print(f"Pipeline loaded on {device} with dtype {dtype}")
184
+
185
+ return pipe
186
+
187
+ def load_style(style_name):
188
+ """Load a textual inversion style"""
189
+ global current_style, pipe
190
+
191
+ if pipe is None:
192
+ initialize_pipeline()
193
+
194
+ if style_name != current_style:
195
+ style_config = STYLES[style_name]
196
+ print(f"Loading style: {style_name}")
197
+ device = "cuda" if torch.cuda.is_available() else "cpu"
198
+
199
+ # Load the inversion
200
+ pipe.load_textual_inversion(style_config["repo"])
201
+
202
+ # Crucial: move back to device as load_textual_inversion
203
+ # can sometimes mess with device placement of embeddings
204
+ pipe.to(device)
205
+
206
+ current_style = style_name
207
+ print(f"Style loaded and verified on {device}")
208
+
209
+ def generate_image(prompt, style_name, seed, num_inference_steps, guidance_scale, contrast_scale, complexity_scale, vibrancy_scale, num_images=3):
210
+ """Generate multiple images with the selected style"""
211
+ try:
212
+ load_style(style_name)
213
+ style_token = STYLES[style_name]["token"]
214
+ final_prompt = prompt.replace("<style>", style_token)
215
+ device = "cuda" if torch.cuda.is_available() else "cpu"
216
+ pipe.to(device)
217
+ generator = torch.Generator(device=device).manual_seed(seed)
218
+ print(f"Generating {num_images} images: '{final_prompt}' with seed {seed}, contrast {contrast_scale}, complexity {complexity_scale}, vibrancy {vibrancy_scale}")
219
+ if contrast_scale > 0 or complexity_scale > 0 or vibrancy_scale > 0:
220
+ images = custom_sampling_loop(final_prompt, pipe, guidance_scale=guidance_scale, contrast_scale=contrast_scale, complexity_scale=complexity_scale, vibrancy_scale=vibrancy_scale, num_inference_steps=num_inference_steps, generator=generator, num_images=int(num_images))
221
+ else:
222
+ result = pipe([final_prompt] * int(num_images), num_inference_steps=num_inference_steps, guidance_scale=guidance_scale, generator=generator)
223
+ images = result.images
224
+ info_text = f"**Style:** {style_name}\n**Seed:** {seed}\n**Prompt:** {final_prompt}\n**Contrast:** {contrast_scale}\n**Complexity:** {complexity_scale}\n**Vibrancy:** {vibrancy_scale}\n**Images Generated:** {len(images)}"
225
+ return images, info_text
226
+ except Exception as e:
227
+ import traceback
228
+ traceback.print_exc()
229
+ return None, f"Error: {str(e)}"
230
+
231
+ def get_default_seed(style_name):
232
+ """Get the default seed for a specific style"""
233
+ return STYLES[style_name]["default_seed"]
234
+
235
+ def generate_all_styles(prompt, seed1, seed2, seed3, seed4, seed5, seed6, num_inference_steps, guidance_scale, contrast_scale, complexity_scale, vibrancy_scale, num_images_per_style):
236
+ """Generate multiple images for all 6 styles with individual seeds"""
237
+ all_images = []
238
+ info_texts = []
239
+ seeds = [seed1, seed2, seed3, seed4, seed5, seed6]
240
+ for idx, (style_name, seed) in enumerate(zip(STYLES.keys(), seeds)):
241
+ style_images, info = generate_image(prompt, style_name, int(seed), num_inference_steps, guidance_scale, contrast_scale=contrast_scale, complexity_scale=complexity_scale, vibrancy_scale=vibrancy_scale, num_images=num_images_per_style)
242
+ all_images.append(style_images)
243
+ info_texts.append(info)
244
+ return all_images[0], all_images[1], all_images[2], all_images[3], all_images[4], all_images[5], "\n\n---\n\n".join(info_texts)
245
+
246
+ # Create Gradio interface
247
+ with gr.Blocks(title="Stable Diffusion Style Explorer", theme=gr.themes.Soft()) as demo:
248
+ gr.Markdown("""
249
+ # 🎨 Stable Diffusion Style Explorer
250
+
251
+ Generate images using different textual inversion styles from the SD Concepts Library.
252
+
253
+ **Tip:** Use `<style>` in your prompt as a placeholder - it will be replaced with the appropriate style token.
254
+ """)
255
+
256
+ with gr.Tabs():
257
+ # Tab 1: Single Style Generation
258
+ with gr.Tab("Single Style"):
259
+ with gr.Row():
260
+ with gr.Column():
261
+ prompt_single = gr.Textbox(
262
+ label="Prompt",
263
+ placeholder="a grafitti in a favela wall with a <style> on it",
264
+ value="a grafitti in a favela wall with a <style> on it",
265
+ lines=3
266
+ )
267
+
268
+ style_dropdown = gr.Dropdown(
269
+ choices=list(STYLES.keys()),
270
+ value=list(STYLES.keys())[0],
271
+ label="Select Style"
272
+ )
273
+
274
+ with gr.Row():
275
+ seed_single = gr.Number(
276
+ label="Seed",
277
+ value=STYLES[list(STYLES.keys())[0]]["default_seed"],
278
+ precision=0
279
+ )
280
+
281
+ steps_single = gr.Slider(
282
+ minimum=10,
283
+ maximum=100,
284
+ value=50,
285
+ step=1,
286
+ label="Inference Steps"
287
+ )
288
+
289
+ guidance_single = gr.Slider(
290
+ minimum=1,
291
+ maximum=20,
292
+ value=7.5,
293
+ step=0.5,
294
+ label="Guidance Scale"
295
+ )
296
+
297
+ with gr.Column(variant="panel"):
298
+ gr.Markdown("### 🎨 Loss Functions")
299
+ contrast_single = gr.Slider(
300
+ minimum=0,
301
+ maximum=2000,
302
+ value=0,
303
+ step=50,
304
+ label="Contrast Strength",
305
+ info="Steer generation towards higher contrast"
306
+ )
307
+
308
+ complexity_single = gr.Slider(
309
+ minimum=0,
310
+ maximum=2000,
311
+ value=0,
312
+ step=50,
313
+ label="Complexity Strength",
314
+ info="Steer generation towards higher detail/edges"
315
+ )
316
+
317
+ vibrancy_single = gr.Slider(
318
+ minimum=0,
319
+ maximum=2000,
320
+ value=0,
321
+ step=50,
322
+ label="Vibrancy Strength",
323
+ info="Steer generation towards higher saturation"
324
+ )
325
+
326
+ num_images_single = gr.Slider(
327
+ minimum=1,
328
+ maximum=4,
329
+ value=3,
330
+ step=1,
331
+ label="Number of Images"
332
+ )
333
+
334
+ generate_btn = gr.Button("Generate Images", variant="primary")
335
+
336
+ with gr.Column():
337
+ output_gallery = gr.Gallery(label="Generated Images", show_label=False, elem_id="gallery", columns=[3], rows=[1], object_fit="contain", height="auto")
338
+ output_info = gr.Markdown()
339
+
340
+ # Update seed when style changes
341
+ style_dropdown.change(
342
+ fn=get_default_seed,
343
+ inputs=[style_dropdown],
344
+ outputs=[seed_single]
345
+ )
346
+
347
+ generate_btn.click(
348
+ fn=generate_image,
349
+ inputs=[prompt_single, style_dropdown, seed_single, steps_single, guidance_single, contrast_single, complexity_single, vibrancy_single, num_images_single],
350
+ outputs=[output_gallery, output_info]
351
+ )
352
+
353
+ # Tab 2: All Styles Comparison
354
+ with gr.Tab("Compare All Styles"):
355
+ gr.Markdown("""
356
+ Generate the same prompt across all 6 styles.
357
+
358
+ **Default seeds** are pre-configured for each style, but you can override them below.
359
+ """)
360
+
361
+ with gr.Row():
362
+ with gr.Column(scale=1):
363
+ prompt_all = gr.Textbox(
364
+ label="Prompt",
365
+ placeholder="a grafitti in a favela wall with a <style> on it",
366
+ value="a grafitti in a favela wall with a <style> on it",
367
+ lines=3
368
+ )
369
+
370
+ gr.Markdown("### 🎲 Seed Configuration")
371
+ gr.Markdown("*Each style has a default seed. Override below if desired.*")
372
+
373
+ style_names = list(STYLES.keys())
374
+ with gr.Row():
375
+ seed1 = gr.Number(
376
+ label=f"🎨 {style_names[0]} Seed",
377
+ value=STYLES[style_names[0]]["default_seed"],
378
+ precision=0,
379
+ info=f"Default: {STYLES[style_names[0]]['default_seed']}"
380
+ )
381
+ seed2 = gr.Number(
382
+ label=f"🎨 {style_names[1]} Seed",
383
+ value=STYLES[style_names[1]]["default_seed"],
384
+ precision=0,
385
+ info=f"Default: {STYLES[style_names[1]]['default_seed']}"
386
+ )
387
+
388
+ with gr.Row():
389
+ seed3 = gr.Number(
390
+ label=f"🎨 {style_names[2]} Seed",
391
+ value=STYLES[style_names[2]]["default_seed"],
392
+ precision=0,
393
+ info=f"Default: {STYLES[style_names[2]]['default_seed']}"
394
+ )
395
+ seed4 = gr.Number(
396
+ label=f"🎨 {style_names[3]} Seed",
397
+ value=STYLES[style_names[3]]["default_seed"],
398
+ precision=0,
399
+ info=f"Default: {STYLES[style_names[3]]['default_seed']}"
400
+ )
401
+
402
+ with gr.Row():
403
+ seed5 = gr.Number(
404
+ label=f"🎨 {style_names[4]} Seed",
405
+ value=STYLES[style_names[4]]["default_seed"],
406
+ precision=0,
407
+ info=f"Default: {STYLES[style_names[4]]['default_seed']}"
408
+ )
409
+ seed6 = gr.Number(
410
+ label=f"🎨 {style_names[5]} Seed",
411
+ value=STYLES[style_names[5]]["default_seed"],
412
+ precision=0,
413
+ info=f"Default: {STYLES[style_names[5]]['default_seed']}"
414
+ )
415
+
416
+ steps_all = gr.Slider(
417
+ minimum=10,
418
+ maximum=100,
419
+ value=50,
420
+ step=1,
421
+ label="Inference Steps"
422
+ )
423
+
424
+ guidance_all = gr.Slider(
425
+ minimum=1,
426
+ maximum=20,
427
+ value=7.5,
428
+ step=0.5,
429
+ label="Guidance Scale"
430
+ )
431
+
432
+ with gr.Column(variant="panel"):
433
+ gr.Markdown("### 🎨 Loss Functions")
434
+ contrast_all = gr.Slider(
435
+ minimum=0,
436
+ maximum=2000,
437
+ value=0,
438
+ step=50,
439
+ label="Contrast Strength",
440
+ info="Steer generation towards higher contrast"
441
+ )
442
+
443
+ complexity_all = gr.Slider(
444
+ minimum=0,
445
+ maximum=2000,
446
+ value=0,
447
+ step=50,
448
+ label="Complexity Strength",
449
+ info="Steer generation towards higher detail/edges"
450
+ )
451
+
452
+ vibrancy_all = gr.Slider(
453
+ minimum=0,
454
+ maximum=2000,
455
+ value=0,
456
+ step=50,
457
+ label="Vibrancy Strength",
458
+ info="Steer generation towards higher saturation"
459
+ )
460
+
461
+ num_images_all = gr.Slider(
462
+ minimum=1,
463
+ maximum=4,
464
+ value=3,
465
+ step=1,
466
+ label="Number of Images per Style"
467
+ )
468
+
469
+ generate_all_btn = gr.Button("Generate All Styles", variant="primary")
470
+
471
+ with gr.Row():
472
+ style_names = list(STYLES.keys())
473
+ output1 = gr.Gallery(label=style_names[0], columns=[3], object_fit="contain", height="auto")
474
+ output2 = gr.Gallery(label=style_names[1], columns=[3], object_fit="contain", height="auto")
475
+ output3 = gr.Gallery(label=style_names[2], columns=[3], object_fit="contain", height="auto")
476
+
477
+ with gr.Row():
478
+ output4 = gr.Gallery(label=style_names[3], columns=[3], object_fit="contain", height="auto")
479
+ output5 = gr.Gallery(label=style_names[4], columns=[3], object_fit="contain", height="auto")
480
+ output6 = gr.Gallery(label=style_names[5], columns=[3], object_fit="contain", height="auto")
481
+
482
+ output_info_all = gr.Markdown()
483
+
484
+ generate_all_btn.click(
485
+ fn=generate_all_styles,
486
+ inputs=[prompt_all, seed1, seed2, seed3, seed4, seed5, seed6, steps_all, guidance_all, contrast_all, complexity_all, vibrancy_all, num_images_all],
487
+ outputs=[output1, output2, output3, output4, output5, output6, output_info_all]
488
+ )
489
+
490
+ gr.Markdown("""
491
+ ---
492
+ ### πŸ“š Available Styles
493
+ """)
494
+
495
+ for style_name, config in STYLES.items():
496
+ gr.Markdown(f"**{style_name}**: {config['description']} | Token: `{config['token']}` | Default Seed: `{config['default_seed']}`")
497
+
498
+ # Initialize pipeline on startup
499
+ initialize_pipeline()
500
+
501
+ # Launch the app
502
+ if __name__ == "__main__":
503
+ demo.launch(share=False)
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ gradio
2
+ torch
3
+ torchvision
4
+ diffusers
5
+ transformers
6
+ accelerate
7
+ huggingface-hub>=0.34.0,<1.0
8
+ Pillow
9
+ safetensors