riasadhuq10 commited on
Commit
bca8078
·
1 Parent(s): d25dd7b

Rolled back to decoupled zimage and hunyuan 3d, removed redundant dependencies

Browse files
Files changed (2) hide show
  1. inner_layer/models/zimage/zimage.py +39 -122
  2. requirements.txt +44 -81
inner_layer/models/zimage/zimage.py CHANGED
@@ -1,153 +1,72 @@
1
  import io
2
  import base64
3
- import torch
4
- from diffusers import ZImagePipeline, FlowMatchEulerDiscreteScheduler
5
- from sdnq import SDNQConfig # import sdnq to register it into diffusers and transformers
6
- from sdnq.common import use_torch_compile as triton_is_available
7
- from sdnq.loader import apply_sdnq_options_to_model
8
- from pathlib import Path
9
  import uuid
10
- import trimesh
11
- import numpy as np
12
  from PIL import Image
 
 
 
13
 
14
-
15
  def ensure_dir(path: str):
16
  Path(path).mkdir(parents=True, exist_ok=True)
17
 
18
- # Global variable to store the loaded model
19
- _zimage_pipe = None
20
-
21
-
22
- def get_zimage_pipeline():
23
- """
24
- Lazily load and return the global Z-Image-Turbo pipeline.
25
- This prevents reloading the model every time the API is called.
26
- """
27
- global _zimage_pipe
28
-
29
- if _zimage_pipe is None:
30
- device = get_best_device()
31
- print(f"[ZImage] Using device: {device}")
32
- print(f"[ZImage] Loading Z-Image-Turbo on {device}...")
33
-
34
- # Use bfloat16 for better quality
35
- dtype = torch.bfloat16 if device in ["mps", "cuda"] else torch.float32
36
-
37
- _zimage_pipe = ZImagePipeline.from_pretrained(
38
- "Disty0/Z-Image-Turbo-SDNQ-uint4-svd-r32",
39
- torch_dtype=dtype,
40
- low_cpu_mem_usage=True,
41
- )
42
-
43
- _zimage_pipe.scheduler = FlowMatchEulerDiscreteScheduler.from_config(
44
- _zimage_pipe.scheduler.config,
45
- use_beta_sigmas=True,
46
- )
47
-
48
- _zimage_pipe.to(device)
49
-
50
- # if triton_is_available and (torch.cuda.is_available() or torch.xpu.is_available()):
51
- # _zimage_pipe.transformer = apply_sdnq_options_to_model(_zimage_pipe.transformer, use_quantized_matmul=True)
52
- # _zimage_pipe.text_encoder = apply_sdnq_options_to_model(_zimage_pipe.text_encoder, use_quantized_matmul=True)
53
- # _zimage_pipe.transformer = torch.compile(_zimage_pipe.transformer) # optional for faster speeds
54
-
55
- _zimage_pipe.enable_model_cpu_offload()
56
-
57
-
58
- _zimage_pipe.enable_attention_slicing()
59
-
60
- # if hasattr(_zimage_pipe, "enable_vae_slicing"):
61
- # _zimage_pipe.enable_vae_slicing()
62
- # print("[ZImage] VAE slicing enabled")
63
-
64
- # if hasattr(getattr(_zimage_pipe, "vae", None), "enable_tiling"):
65
- # _zimage_pipe.vae.enable_tiling()
66
- # print("[ZImage] VAE tiling enabled")
67
- # print("[ZImage] Model loaded successfully.")
68
- return _zimage_pipe
69
-
70
- import torch
71
-
72
- def get_best_device():
73
- if torch.cuda.is_available():
74
- return "cuda"
75
- elif torch.version.hip is not None: # ROCm (AMD)
76
- return "hip"
77
- elif torch.backends.mps.is_available():
78
- return "mps"
79
- elif torch.backends.mps.is_built(): # fallback in case of MPS build but not available
80
- return "mps"
81
- elif torch.backends.opencl.is_available(): # not always present, but check
82
- return "opencl"
83
- elif torch.has_mps: # just in case for Apple
84
- return "mps"
85
- else:
86
- return "cpu"
87
-
88
-
89
  def image_to_glb(image: Image.Image, thickness: float = 0.001) -> bytes:
90
  w, h = image.size
91
  aspect = w / h
92
 
93
- # Thin box so viewers don’t cull it
94
- mesh = trimesh.creation.box(
95
- extents=(aspect, 1.0, thickness)
96
- )
97
 
98
- # Simple UV mapping
99
  uv = np.zeros((len(mesh.vertices), 2))
100
  uv[:, 0] = (mesh.vertices[:, 0] / aspect + 0.5)
101
  uv[:, 1] = (mesh.vertices[:, 1] + 0.5)
102
 
103
- mesh.visual = trimesh.visual.TextureVisuals(
104
- uv=uv,
105
- image=image
106
- )
107
-
108
  return mesh.export(file_type="glb")
109
 
110
 
 
 
 
 
 
 
 
 
 
 
111
  def generate_image_base64(
112
  prompt: str,
113
  height: int = 768,
114
  width: int = 768,
115
- steps: int = 50,
116
  seed: int = 5,
117
  convert_to_glb: bool = False,
 
118
  ) -> str:
119
  """
120
- Generate an image from text prompt using Z-Image-Turbo.
121
  Returns:
122
  - base64 PNG if convert_to_glb=False
123
  - base64 GLB if convert_to_glb=True
124
  """
125
- pipe = get_zimage_pipeline()
126
-
127
- if seed is None:
128
- seed = torch.randint(0, 2**32, (1,)).item()
129
- print(f"Generating with seed {seed}...")
130
-
131
- device = get_best_device()
132
-
133
- if device == "cuda":
134
- generator = torch.Generator("cuda").manual_seed(seed)
135
- elif device == "mps":
136
- generator = torch.Generator("mps").manual_seed(seed)
137
- else:
138
- generator = torch.Generator().manual_seed(seed)
139
 
140
- with torch.inference_mode():
141
- result = pipe(
142
- prompt=prompt,
143
- height=height,
144
- width=width,
145
- num_inference_steps=steps,
146
- guidance_scale=0.0,
147
- generator=generator,
148
- )
149
 
150
- image = result.images[0]
151
 
152
  ensure_dir("output/images")
153
  img_name = f"zimage_{uuid.uuid4().hex}.png"
@@ -155,19 +74,17 @@ def generate_image_base64(
155
  image.save(img_path)
156
  print(f"[ZImage] Saved image to {img_path}")
157
 
158
- # --- If GLB is NOT requested, return image ---
159
  if not convert_to_glb:
160
 
161
  return img_path
162
 
163
- # --- Convert to GLB only if requested ---
164
  glb_bytes = image_to_glb(image)
165
-
166
  glb_name = f"zimage_{uuid.uuid4().hex}.glb"
167
  glb_path = Path("output/images") / glb_name
168
  with open(glb_path, "wb") as f:
169
  f.write(glb_bytes)
 
170
 
171
- print(f"[ZImage] Saved glb to {glb_path}")
172
-
173
- return base64.b64encode(glb_bytes).decode("utf-8")
 
1
  import io
2
  import base64
 
 
 
 
 
 
3
  import uuid
4
+ from pathlib import Path
 
5
  from PIL import Image
6
+ import numpy as np
7
+ import trimesh
8
+ from gradio_client import Client
9
 
10
+ # --- Ensure output directories ---
11
  def ensure_dir(path: str):
12
  Path(path).mkdir(parents=True, exist_ok=True)
13
 
14
+ # --- Convert PIL image to GLB ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  def image_to_glb(image: Image.Image, thickness: float = 0.001) -> bytes:
16
  w, h = image.size
17
  aspect = w / h
18
 
19
+ mesh = trimesh.creation.box(extents=(aspect, 1.0, thickness))
 
 
 
20
 
 
21
  uv = np.zeros((len(mesh.vertices), 2))
22
  uv[:, 0] = (mesh.vertices[:, 0] / aspect + 0.5)
23
  uv[:, 1] = (mesh.vertices[:, 1] + 0.5)
24
 
25
+ mesh.visual = trimesh.visual.TextureVisuals(uv=uv, image=image)
 
 
 
 
26
  return mesh.export(file_type="glb")
27
 
28
 
29
+ # --- Global Gradio client ---
30
+ _client = None
31
+ def get_gradio_client():
32
+ global _client
33
+ if _client is None:
34
+ _client = Client("mrfakename/Z-Image-Turbo")
35
+ return _client
36
+
37
+
38
+ # --- Main image generation function ---
39
  def generate_image_base64(
40
  prompt: str,
41
  height: int = 768,
42
  width: int = 768,
43
+ steps: int = 8,
44
  seed: int = 5,
45
  convert_to_glb: bool = False,
46
+ randomize_seed: bool = True,
47
  ) -> str:
48
  """
49
+ Generate an image from text prompt using Gradio Z-Image-Turbo.
50
  Returns:
51
  - base64 PNG if convert_to_glb=False
52
  - base64 GLB if convert_to_glb=True
53
  """
54
+ client = get_gradio_client()
55
+
56
+ # Predict using the Gradio API
57
+ result, used_seed = client.predict(
58
+ prompt=prompt,
59
+ height=height,
60
+ width=width,
61
+ num_inference_steps=steps,
62
+ seed=seed,
63
+ randomize_seed=randomize_seed,
64
+ api_name="/generate_image"
65
+ )
 
 
66
 
67
+
 
 
 
 
 
 
 
 
68
 
69
+ image = Image.open(result)
70
 
71
  ensure_dir("output/images")
72
  img_name = f"zimage_{uuid.uuid4().hex}.png"
 
74
  image.save(img_path)
75
  print(f"[ZImage] Saved image to {img_path}")
76
 
77
+ # --- Return PNG base64 ---
78
  if not convert_to_glb:
79
 
80
  return img_path
81
 
82
+ # --- Convert to GLB ---
83
  glb_bytes = image_to_glb(image)
 
84
  glb_name = f"zimage_{uuid.uuid4().hex}.glb"
85
  glb_path = Path("output/images") / glb_name
86
  with open(glb_path, "wb") as f:
87
  f.write(glb_bytes)
88
+ print(f"[ZImage] Saved GLB to {glb_path}")
89
 
90
+ return base64.b64encode(glb_bytes).decode("utf-8")
 
 
requirements.txt CHANGED
@@ -1,139 +1,102 @@
1
- accelerate==1.12.0
2
  aiohappyeyeballs==2.6.1
3
- aiohttp==3.13.2
4
  aiosignal==1.4.0
5
  annotated-doc==0.0.4
6
  annotated-types==0.7.0
7
- anyio==4.12.0
8
- async-timeout==5.0.1
9
  attrs==25.4.0
10
- Authlib==1.6.6
11
- backports.tarfile==1.2.0
12
  beartype==0.22.9
13
- cachetools==6.2.3
14
- certifi==2025.11.12
15
  cffi==2.0.0
16
  charset-normalizer==3.4.4
17
  click==8.3.1
18
  cloudpickle==3.1.2
19
- coloredlogs==15.0.1
20
- cryptography==46.0.3
21
- cyclopts==4.3.0
22
- diffusers @ git+https://github.com/huggingface/diffusers@17c0e79dbdf53fb6705e9c09cc1a854b84c39249
23
  diskcache==5.6.3
24
  dnspython==2.8.0
25
  docstring_parser==0.17.0
26
- docutils==0.22.3
27
  email-validator==2.3.0
28
  exceptiongroup==1.3.1
29
- fakeredis==2.32.1
30
- fastapi==0.124.4
31
- fastapi-mcp==0.4.0
32
- fastmcp==2.14.0
33
- filelock==3.20.0
34
- flatbuffers==25.9.23
35
  frozenlist==1.8.0
36
- fsspec==2025.12.0
 
37
  h11==0.16.0
38
  hf-xet==1.2.0
39
  httpcore==1.0.9
40
  httpx==0.28.1
41
  httpx-sse==0.4.3
42
- huggingface-hub==0.36.0
43
- humanfriendly==10.0
44
  idna==3.11
45
  ImageIO==2.37.2
46
- importlib_metadata==8.7.0
47
  jaraco.classes==3.4.0
48
- jaraco.context==6.0.1
49
- jaraco.functools==4.3.0
50
- Jinja2==3.1.6
51
- jsonschema==4.25.1
52
  jsonschema-path==0.3.4
53
  jsonschema-specifications==2025.9.1
54
  keyring==25.7.0
55
- lazy_loader==0.4
56
- llvmlite==0.46.0
57
  lupa==2.6
58
  markdown-it-py==4.0.0
59
- MarkupSafe==3.0.3
60
- mcp==1.24.0
61
  mdurl==0.1.2
62
  more-itertools==10.8.0
63
- mpmath==1.3.0
64
- multidict==6.7.0
65
- networkx==3.4.2
66
- numba==0.63.1
67
- numpy==2.2.6
68
- onnxruntime==1.23.2
69
  openapi-pydantic==0.5.1
70
- opencv-python-headless==4.12.0.88
71
  opentelemetry-api==1.39.1
72
- opentelemetry-exporter-prometheus==0.60b1
73
- opentelemetry-instrumentation==0.60b1
74
- opentelemetry-sdk==1.39.1
75
- opentelemetry-semantic-conventions==0.60b1
76
- packaging==25.0
77
  pathable==0.4.4
78
  pathvalidate==3.3.1
79
- pillow==12.0.0
80
  platformdirs==4.5.1
81
- pooch==1.8.2
82
- prometheus_client==0.23.1
83
  propcache==0.4.1
84
- protobuf==6.33.2
85
- psutil==7.1.3
86
  py-key-value-aio==0.3.0
87
  py-key-value-shared==0.3.0
88
- pybind11==3.0.1
89
- pycparser==2.23
90
  pydantic==2.12.5
91
  pydantic-settings==2.12.0
92
  pydantic_core==2.41.5
93
- pydocket==0.15.5
94
  Pygments==2.19.2
95
- PyJWT==2.10.1
96
- PyMatting==1.1.14
97
  pyperclip==1.11.0
 
98
  python-dotenv==1.2.1
99
  python-json-logger==4.0.0
100
- python-multipart==0.0.20
 
101
  PyYAML==6.0.3
102
  redis==7.1.0
103
  referencing==0.36.2
104
- regex==2025.11.3
105
- rembg==2.0.69
106
  requests==2.32.5
107
- rich==14.2.0
108
  rich-rst==1.3.2
109
  rpds-py==0.30.0
110
- safetensors==0.7.0
111
- scikit-image==0.25.2
112
- scipy==1.15.3
113
- sdnq==0.1.2
114
  shellingham==1.5.4
 
115
  sortedcontainers==2.4.0
116
- sse-starlette==3.0.3
117
- starlette==0.50.0
118
- sympy==1.14.0
119
- tifffile==2025.5.10
120
- tokenizers==0.22.1
121
- tomli==2.3.0
122
- torch==2.9.1
123
- torchvision==0.24.1
124
- tqdm==4.67.1
125
- transformers==4.57.3
126
- typer==0.20.0
127
- typer-slim==0.20.0
128
  typing-inspection==0.4.2
129
  typing_extensions==4.15.0
130
- urllib3==2.6.2
131
- uvicorn==0.38.0
132
- websockets==15.0.1
133
- wrapt==1.17.3
134
  yarl==1.22.0
135
  zipp==3.23.0
136
-
137
-
138
- trimesh
139
- gradio_client
 
 
1
  aiohappyeyeballs==2.6.1
2
+ aiohttp==3.13.3
3
  aiosignal==1.4.0
4
  annotated-doc==0.0.4
5
  annotated-types==0.7.0
6
+ anyio==4.12.1
 
7
  attrs==25.4.0
8
+ Authlib==1.6.7
 
9
  beartype==0.22.9
10
+ cachetools==7.0.0
11
+ certifi==2026.1.4
12
  cffi==2.0.0
13
  charset-normalizer==3.4.4
14
  click==8.3.1
15
  cloudpickle==3.1.2
16
+ croniter==6.0.0
17
+ cryptography==46.0.4
18
+ cyclopts==4.5.1
 
19
  diskcache==5.6.3
20
  dnspython==2.8.0
21
  docstring_parser==0.17.0
22
+ docutils==0.22.4
23
  email-validator==2.3.0
24
  exceptiongroup==1.3.1
25
+ fakeredis==2.33.0
26
+ fastapi==0.128.4
27
+ fastmcp==2.14.5
28
+ filelock==3.20.3
 
 
29
  frozenlist==1.8.0
30
+ fsspec==2026.2.0
31
+ gradio_client==2.0.3
32
  h11==0.16.0
33
  hf-xet==1.2.0
34
  httpcore==1.0.9
35
  httpx==0.28.1
36
  httpx-sse==0.4.3
37
+ huggingface_hub==1.4.1
 
38
  idna==3.11
39
  ImageIO==2.37.2
40
+ importlib_metadata==8.7.1
41
  jaraco.classes==3.4.0
42
+ jaraco.context==6.1.0
43
+ jaraco.functools==4.4.0
44
+ jsonref==1.1.0
45
+ jsonschema==4.26.0
46
  jsonschema-path==0.3.4
47
  jsonschema-specifications==2025.9.1
48
  keyring==25.7.0
 
 
49
  lupa==2.6
50
  markdown-it-py==4.0.0
51
+ mcp==1.26.0
 
52
  mdurl==0.1.2
53
  more-itertools==10.8.0
54
+ multidict==6.7.1
55
+ numpy==2.4.2
 
 
 
 
56
  openapi-pydantic==0.5.1
 
57
  opentelemetry-api==1.39.1
58
+ packaging==26.0
 
 
 
 
59
  pathable==0.4.4
60
  pathvalidate==3.3.1
61
+ pillow==12.1.0
62
  platformdirs==4.5.1
63
+ prometheus_client==0.24.1
 
64
  propcache==0.4.1
 
 
65
  py-key-value-aio==0.3.0
66
  py-key-value-shared==0.3.0
67
+ pycparser==3.0
 
68
  pydantic==2.12.5
69
  pydantic-settings==2.12.0
70
  pydantic_core==2.41.5
71
+ pydocket==0.17.5
72
  Pygments==2.19.2
73
+ PyJWT==2.11.0
 
74
  pyperclip==1.11.0
75
+ python-dateutil==2.9.0.post0
76
  python-dotenv==1.2.1
77
  python-json-logger==4.0.0
78
+ python-multipart==0.0.22
79
+ pytz==2025.2
80
  PyYAML==6.0.3
81
  redis==7.1.0
82
  referencing==0.36.2
 
 
83
  requests==2.32.5
84
+ rich==14.3.2
85
  rich-rst==1.3.2
86
  rpds-py==0.30.0
 
 
 
 
87
  shellingham==1.5.4
88
+ six==1.17.0
89
  sortedcontainers==2.4.0
90
+ sse-starlette==3.2.0
91
+ starlette==0.52.1
92
+ tqdm==4.67.3
93
+ trimesh==4.11.1
94
+ typer==0.21.1
95
+ typer-slim==0.21.1
 
 
 
 
 
 
96
  typing-inspection==0.4.2
97
  typing_extensions==4.15.0
98
+ urllib3==2.6.3
99
+ uvicorn==0.40.0
100
+ websockets==16.0
 
101
  yarl==1.22.0
102
  zipp==3.23.0