abersbail commited on
Commit
7c3c871
·
verified ·
1 Parent(s): adc22e2

Deploy tiny text to image CPU Space

Browse files
README.md CHANGED
@@ -1,12 +1,31 @@
1
  ---
2
- title: Tiny Text To Image Cpu
3
- emoji: 🏃
4
- colorFrom: yellow
5
- colorTo: yellow
6
  sdk: gradio
7
- sdk_version: 6.9.0
 
8
  app_file: app.py
9
  pinned: false
 
 
10
  ---
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: Tiny Text To Image CPU
3
+ colorFrom: blue
4
+ colorTo: indigo
 
5
  sdk: gradio
6
+ sdk_version: 5.23.0
7
+ python_version: "3.10"
8
  app_file: app.py
9
  pinned: false
10
+ models:
11
+ - segmind/tiny-sd
12
  ---
13
 
14
+ # Tiny Text To Image CPU
15
+
16
+ This is a separate lightweight Hugging Face Space for text-to-image generation on free CPU hardware.
17
+
18
+ Model:
19
+ - `segmind/tiny-sd`
20
+
21
+ Features:
22
+ - Compact text-to-image model
23
+ - CPU-oriented generation defaults
24
+ - Style presets
25
+ - Separate deployment from the TTS Spaces
26
+ - No user token stored in the Space
27
+
28
+ ## Notes
29
+
30
+ - This Space is designed for free CPU hardware, so generation is slower and image quality is lower than large GPU models.
31
+ - The first request takes longer because the model downloads inside the Space.
__pycache__/app.cpython-313.pyc ADDED
Binary file (3.58 kB). View file
 
app.py ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+
3
+ from tiny_image_gen.catalog import STYLE_PRESETS, default_prompt, style_choices
4
+ from tiny_image_gen.service import TinyImageService
5
+
6
+
7
+ service = TinyImageService()
8
+
9
+
10
+ def update_style(style_name: str):
11
+ return STYLE_PRESETS[style_name].hint
12
+
13
+
14
+ def run_generation(prompt: str, style_name: str, negative_prompt: str, steps: int, guidance: float, seed: int):
15
+ return service.generate(
16
+ prompt=prompt,
17
+ style_name=style_name,
18
+ negative_prompt=negative_prompt,
19
+ steps=steps,
20
+ guidance=guidance,
21
+ seed=seed,
22
+ )
23
+
24
+
25
+ with gr.Blocks(title="Tiny Text To Image CPU") as demo:
26
+ gr.Markdown(
27
+ """
28
+ # Tiny Text To Image CPU
29
+ Small text-to-image generation running on a free CPU Space.
30
+
31
+ - Model: `segmind/tiny-sd`
32
+ - Separate Space
33
+ - CPU-friendly defaults
34
+ - Single-image generation
35
+ """
36
+ )
37
+
38
+ with gr.Row():
39
+ with gr.Column():
40
+ prompt = gr.Textbox(
41
+ label="Prompt",
42
+ value=default_prompt(),
43
+ lines=6,
44
+ )
45
+ style = gr.Dropdown(
46
+ label="Style",
47
+ choices=style_choices(),
48
+ value="Cinematic",
49
+ )
50
+ style_hint = gr.Textbox(
51
+ label="Style Hint",
52
+ value=STYLE_PRESETS["Cinematic"].hint,
53
+ interactive=False,
54
+ lines=3,
55
+ )
56
+ negative_prompt = gr.Textbox(
57
+ label="Negative Prompt",
58
+ value="blurry, low quality, distorted, deformed, extra fingers, watermark, text",
59
+ lines=3,
60
+ )
61
+ steps = gr.Slider(
62
+ label="Steps",
63
+ minimum=4,
64
+ maximum=20,
65
+ value=10,
66
+ step=1,
67
+ )
68
+ guidance = gr.Slider(
69
+ label="Guidance Scale",
70
+ minimum=1.0,
71
+ maximum=10.0,
72
+ value=6.0,
73
+ step=0.5,
74
+ )
75
+ seed = gr.Number(
76
+ label="Seed",
77
+ value=42,
78
+ precision=0,
79
+ )
80
+ generate = gr.Button("Generate Image", variant="primary")
81
+
82
+ with gr.Column():
83
+ image = gr.Image(label="Image", type="pil")
84
+ status = gr.Textbox(label="Status", value=service.describe())
85
+ info = gr.Textbox(
86
+ label="Info",
87
+ value="This Space uses a compact diffusion model, so quality is lower than large GPU models but it fits free CPU hardware better.",
88
+ lines=6,
89
+ )
90
+
91
+ style.change(
92
+ fn=update_style,
93
+ inputs=style,
94
+ outputs=style_hint,
95
+ )
96
+
97
+ generate.click(
98
+ fn=run_generation,
99
+ inputs=[prompt, style, negative_prompt, steps, guidance, seed],
100
+ outputs=[image, status, info],
101
+ )
102
+
103
+
104
+ if __name__ == "__main__":
105
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ accelerate>=0.33.0
2
+ diffusers>=0.31.0
3
+ gradio==5.23.0
4
+ Pillow>=10.0.0
5
+ safetensors>=0.4.4
6
+ torch>=2.3.0
7
+ transformers>=4.46.1
tiny_image_gen/__init__.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from .service import TinyImageService
2
+
3
+ __all__ = ["TinyImageService"]
tiny_image_gen/__pycache__/__init__.cpython-313.pyc ADDED
Binary file (202 Bytes). View file
 
tiny_image_gen/__pycache__/catalog.cpython-313.pyc ADDED
Binary file (1.74 kB). View file
 
tiny_image_gen/__pycache__/service.cpython-313.pyc ADDED
Binary file (4.53 kB). View file
 
tiny_image_gen/catalog.py ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dataclasses import dataclass
2
+
3
+
4
+ @dataclass(frozen=True)
5
+ class StylePreset:
6
+ suffix: str
7
+ hint: str
8
+
9
+
10
+ STYLE_PRESETS = {
11
+ "Cinematic": StylePreset(
12
+ suffix="cinematic lighting, highly detailed, dramatic composition, rich colors",
13
+ hint="Adds film-like lighting and richer detail.",
14
+ ),
15
+ "Anime": StylePreset(
16
+ suffix="anime style, clean line art, vibrant colors, expressive composition",
17
+ hint="Pushes the output toward anime illustration.",
18
+ ),
19
+ "Fantasy": StylePreset(
20
+ suffix="fantasy art, magical atmosphere, detailed environment, epic scene",
21
+ hint="Adds a fantasy painting look.",
22
+ ),
23
+ "Pixel Art": StylePreset(
24
+ suffix="pixel art, retro game sprite style, sharp edges, limited color palette",
25
+ hint="Pushes toward retro pixel-art aesthetics.",
26
+ ),
27
+ "Photographic": StylePreset(
28
+ suffix="photo realistic, natural light, realistic detail, professional photography",
29
+ hint="Pushes toward a photographic look.",
30
+ ),
31
+ }
32
+
33
+
34
+ def style_choices() -> list[str]:
35
+ return list(STYLE_PRESETS.keys())
36
+
37
+
38
+ def default_prompt() -> str:
39
+ return "A futuristic city street at sunset with neon reflections after rain"
tiny_image_gen/service.py ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import random
2
+ from threading import Lock
3
+
4
+ import gradio as gr
5
+ import torch
6
+ from diffusers import StableDiffusionPipeline
7
+
8
+ from .catalog import STYLE_PRESETS
9
+
10
+
11
+ MODEL_ID = "segmind/tiny-sd"
12
+ DEVICE = "cpu"
13
+ IMAGE_SIZE = 384
14
+ BLOCKED_TERMS = {
15
+ "child sexual",
16
+ "sexual minor",
17
+ "rape",
18
+ "gore torture",
19
+ }
20
+
21
+
22
+ class TinyImageService:
23
+ def __init__(self):
24
+ self._lock = Lock()
25
+ self._pipe = None
26
+ torch.set_num_threads(4)
27
+
28
+ def describe(self) -> str:
29
+ return "Tiny image generator ready. The model loads on first use."
30
+
31
+ def _ensure_pipe(self):
32
+ with self._lock:
33
+ if self._pipe is not None:
34
+ return
35
+
36
+ pipe = StableDiffusionPipeline.from_pretrained(
37
+ MODEL_ID,
38
+ torch_dtype=torch.float32,
39
+ safety_checker=None,
40
+ requires_safety_checker=False,
41
+ low_cpu_mem_usage=True,
42
+ use_safetensors=True,
43
+ )
44
+ pipe = pipe.to(DEVICE)
45
+ pipe.enable_attention_slicing()
46
+ pipe.enable_vae_slicing()
47
+ pipe.set_progress_bar_config(disable=True)
48
+ self._pipe = pipe
49
+
50
+ def generate(
51
+ self,
52
+ prompt: str,
53
+ style_name: str,
54
+ negative_prompt: str,
55
+ steps: int,
56
+ guidance: float,
57
+ seed: int,
58
+ ):
59
+ clean_prompt = " ".join(prompt.split())
60
+ clean_negative = " ".join(negative_prompt.split())
61
+ if not clean_prompt:
62
+ raise gr.Error("Prompt is required.")
63
+
64
+ lowered = clean_prompt.lower()
65
+ if any(term in lowered for term in BLOCKED_TERMS):
66
+ raise gr.Error("Prompt is not allowed.")
67
+
68
+ style = STYLE_PRESETS[style_name]
69
+ final_prompt = f"{clean_prompt}, {style.suffix}"
70
+ self._ensure_pipe()
71
+
72
+ seed_value = int(seed) if seed is not None else random.randint(1, 2**31 - 1)
73
+ generator = torch.Generator(device=DEVICE).manual_seed(seed_value)
74
+
75
+ with self._lock:
76
+ result = self._pipe(
77
+ prompt=final_prompt,
78
+ negative_prompt=clean_negative or None,
79
+ num_inference_steps=int(steps),
80
+ guidance_scale=float(guidance),
81
+ width=IMAGE_SIZE,
82
+ height=IMAGE_SIZE,
83
+ generator=generator,
84
+ )
85
+
86
+ image = result.images[0]
87
+ status = f"Generated image with {MODEL_ID} on CPU. Seed={seed_value}."
88
+ info = (
89
+ f"Final prompt:\n{final_prompt}\n\n"
90
+ f"Negative prompt:\n{clean_negative or 'None'}\n\n"
91
+ f"Steps: {int(steps)} | Guidance: {float(guidance):.1f} | Size: {IMAGE_SIZE}x{IMAGE_SIZE}"
92
+ )
93
+ return image, status, info