xinference 0.15.2__py3-none-any.whl → 0.15.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of xinference might be problematic. Click here for more details.
- xinference/_version.py +3 -3
- xinference/api/restful_api.py +29 -2
- xinference/client/restful/restful_client.py +10 -0
- xinference/constants.py +4 -0
- xinference/core/image_interface.py +76 -23
- xinference/core/model.py +80 -39
- xinference/core/progress_tracker.py +187 -0
- xinference/core/supervisor.py +11 -0
- xinference/core/worker.py +1 -0
- xinference/model/audio/chattts.py +2 -1
- xinference/model/audio/core.py +0 -2
- xinference/model/audio/model_spec.json +8 -0
- xinference/model/audio/model_spec_modelscope.json +9 -0
- xinference/model/embedding/core.py +14 -5
- xinference/model/embedding/model_spec.json +7 -0
- xinference/model/embedding/model_spec_modelscope.json +9 -1
- xinference/model/image/core.py +6 -7
- xinference/model/image/sdapi.py +35 -4
- xinference/model/image/stable_diffusion/core.py +212 -70
- xinference/model/llm/llm_family.json +28 -40
- xinference/model/llm/llm_family_modelscope.json +18 -22
- xinference/model/llm/transformers/cogvlm2.py +2 -1
- xinference/model/llm/transformers/cogvlm2_video.py +2 -0
- xinference/model/llm/transformers/core.py +6 -2
- xinference/model/llm/transformers/deepseek_vl.py +2 -0
- xinference/model/llm/transformers/glm4v.py +2 -1
- xinference/model/llm/transformers/intern_vl.py +2 -0
- xinference/model/llm/transformers/minicpmv25.py +2 -0
- xinference/model/llm/transformers/minicpmv26.py +2 -0
- xinference/model/llm/transformers/omnilmm.py +2 -0
- xinference/model/llm/transformers/qwen2_audio.py +11 -4
- xinference/model/llm/transformers/qwen2_vl.py +2 -28
- xinference/model/llm/transformers/qwen_vl.py +2 -1
- xinference/model/llm/transformers/utils.py +35 -2
- xinference/model/llm/transformers/yi_vl.py +2 -0
- xinference/model/llm/utils.py +72 -17
- xinference/model/llm/vllm/core.py +69 -9
- xinference/model/llm/vllm/utils.py +41 -0
- xinference/model/rerank/core.py +19 -0
- xinference/model/rerank/model_spec.json +8 -0
- xinference/model/rerank/model_spec_modelscope.json +8 -0
- xinference/model/utils.py +7 -29
- xinference/model/video/core.py +0 -2
- xinference/web/ui/build/asset-manifest.json +3 -3
- xinference/web/ui/build/index.html +1 -1
- xinference/web/ui/build/static/js/{main.29578905.js → main.e51a356d.js} +3 -3
- xinference/web/ui/build/static/js/main.e51a356d.js.map +1 -0
- xinference/web/ui/node_modules/.cache/babel-loader/4385c1095eefbff0a8ec3b2964ba6e5a66a05ab31be721483ca2f43e2a91f6ff.json +1 -0
- {xinference-0.15.2.dist-info → xinference-0.15.4.dist-info}/METADATA +6 -5
- {xinference-0.15.2.dist-info → xinference-0.15.4.dist-info}/RECORD +55 -53
- xinference/web/ui/build/static/js/main.29578905.js.map +0 -1
- xinference/web/ui/node_modules/.cache/babel-loader/68bede6d95bb5ef0b35bbb3ec5b8c937eaf6862c6cdbddb5ef222a7776aaf336.json +0 -1
- /xinference/web/ui/build/static/js/{main.29578905.js.LICENSE.txt → main.e51a356d.js.LICENSE.txt} +0 -0
- {xinference-0.15.2.dist-info → xinference-0.15.4.dist-info}/LICENSE +0 -0
- {xinference-0.15.2.dist-info → xinference-0.15.4.dist-info}/WHEEL +0 -0
- {xinference-0.15.2.dist-info → xinference-0.15.4.dist-info}/entry_points.txt +0 -0
- {xinference-0.15.2.dist-info → xinference-0.15.4.dist-info}/top_level.txt +0 -0
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
|
|
15
15
|
import base64
|
|
16
16
|
import contextlib
|
|
17
|
+
import gc
|
|
17
18
|
import inspect
|
|
19
|
+
import itertools
|
|
18
20
|
import logging
|
|
19
21
|
import os
|
|
20
22
|
import re
|
|
@@ -25,7 +27,7 @@ import warnings
|
|
|
25
27
|
from concurrent.futures import ThreadPoolExecutor
|
|
26
28
|
from functools import partial
|
|
27
29
|
from io import BytesIO
|
|
28
|
-
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
|
|
30
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union
|
|
29
31
|
|
|
30
32
|
import PIL.Image
|
|
31
33
|
import torch
|
|
@@ -37,6 +39,7 @@ from ....types import Image, ImageList, LoRA
|
|
|
37
39
|
from ..sdapi import SDAPIDiffusionModelMixin
|
|
38
40
|
|
|
39
41
|
if TYPE_CHECKING:
|
|
42
|
+
from ....core.progress_tracker import Progressor
|
|
40
43
|
from ..core import ImageModelFamilyV1
|
|
41
44
|
|
|
42
45
|
logger = logging.getLogger(__name__)
|
|
@@ -93,16 +96,21 @@ class DiffusionModel(SDAPIDiffusionModelMixin):
|
|
|
93
96
|
self._model_uid = model_uid
|
|
94
97
|
self._model_path = model_path
|
|
95
98
|
self._device = device
|
|
96
|
-
#
|
|
97
|
-
# it will be loaded as AutoPipelineForText2Image
|
|
98
|
-
# for image2image and inpainting,
|
|
99
|
-
# we convert to the corresponding model
|
|
99
|
+
# model info when loading
|
|
100
100
|
self._model = None
|
|
101
|
-
self._i2i_model = None # image to image model
|
|
102
|
-
self._inpainting_model = None # inpainting model
|
|
103
101
|
self._lora_model = lora_model
|
|
104
102
|
self._lora_load_kwargs = lora_load_kwargs or {}
|
|
105
103
|
self._lora_fuse_kwargs = lora_fuse_kwargs or {}
|
|
104
|
+
# deepcache
|
|
105
|
+
self._deepcache_helper = None
|
|
106
|
+
# when a model has text2image ability,
|
|
107
|
+
# it will be loaded as AutoPipelineForText2Image
|
|
108
|
+
# for image2image and inpainting,
|
|
109
|
+
# we convert to the corresponding model
|
|
110
|
+
self._torch_dtype = None
|
|
111
|
+
self._ability_to_models: Dict[Tuple[str, Any], Any] = {}
|
|
112
|
+
self._controlnet_models: Dict[str, Any] = {}
|
|
113
|
+
# info
|
|
106
114
|
self._model_spec = model_spec
|
|
107
115
|
self._abilities = model_spec.model_ability or [] # type: ignore
|
|
108
116
|
self._kwargs = kwargs
|
|
@@ -111,6 +119,63 @@ class DiffusionModel(SDAPIDiffusionModelMixin):
|
|
|
111
119
|
def model_ability(self):
|
|
112
120
|
return self._abilities
|
|
113
121
|
|
|
122
|
+
@staticmethod
|
|
123
|
+
def _get_pipeline_type(ability: str) -> type:
|
|
124
|
+
if ability == "text2image":
|
|
125
|
+
from diffusers import AutoPipelineForText2Image as AutoPipelineModel
|
|
126
|
+
elif ability == "image2image":
|
|
127
|
+
from diffusers import AutoPipelineForImage2Image as AutoPipelineModel
|
|
128
|
+
elif ability == "inpainting":
|
|
129
|
+
from diffusers import AutoPipelineForInpainting as AutoPipelineModel
|
|
130
|
+
else:
|
|
131
|
+
raise ValueError(f"Unknown ability: {ability}")
|
|
132
|
+
return AutoPipelineModel
|
|
133
|
+
|
|
134
|
+
def _get_controlnet_model(self, name: str, path: str):
|
|
135
|
+
from diffusers import ControlNetModel
|
|
136
|
+
|
|
137
|
+
try:
|
|
138
|
+
return self._controlnet_models[name]
|
|
139
|
+
except KeyError:
|
|
140
|
+
logger.debug("Loading controlnet %s, from %s", name, path)
|
|
141
|
+
model = ControlNetModel.from_pretrained(path, torch_dtype=self._torch_dtype)
|
|
142
|
+
self._controlnet_models[name] = model
|
|
143
|
+
return model
|
|
144
|
+
|
|
145
|
+
def _get_model(
|
|
146
|
+
self,
|
|
147
|
+
ability: str,
|
|
148
|
+
controlnet_name: Optional[Union[str, List[str]]] = None,
|
|
149
|
+
controlnet_path: Optional[Union[str, List[str]]] = None,
|
|
150
|
+
):
|
|
151
|
+
try:
|
|
152
|
+
return self._ability_to_models[ability, controlnet_name]
|
|
153
|
+
except KeyError:
|
|
154
|
+
model_type = self._get_pipeline_type(ability)
|
|
155
|
+
|
|
156
|
+
assert self._model is not None
|
|
157
|
+
|
|
158
|
+
if controlnet_name:
|
|
159
|
+
assert controlnet_path
|
|
160
|
+
if isinstance(controlnet_name, (list, tuple)):
|
|
161
|
+
controlnet = []
|
|
162
|
+
# multiple controlnet
|
|
163
|
+
for name, path in itertools.zip_longest(
|
|
164
|
+
controlnet_name, controlnet_path
|
|
165
|
+
):
|
|
166
|
+
controlnet.append(self._get_controlnet_model(name, path))
|
|
167
|
+
else:
|
|
168
|
+
controlnet = self._get_controlnet_model(
|
|
169
|
+
controlnet_name, controlnet_path
|
|
170
|
+
)
|
|
171
|
+
model = model_type.from_pipe(self._model, controlnet=controlnet)
|
|
172
|
+
else:
|
|
173
|
+
model = model_type.from_pipe(self._model)
|
|
174
|
+
self._load_to_device(model)
|
|
175
|
+
|
|
176
|
+
self._ability_to_models[ability, controlnet_name] = model
|
|
177
|
+
return model
|
|
178
|
+
|
|
114
179
|
def _apply_lora(self):
|
|
115
180
|
if self._lora_model is not None:
|
|
116
181
|
logger.info(
|
|
@@ -132,22 +197,24 @@ class DiffusionModel(SDAPIDiffusionModelMixin):
|
|
|
132
197
|
else:
|
|
133
198
|
raise ValueError(f"Unknown ability: {self._abilities}")
|
|
134
199
|
|
|
135
|
-
|
|
136
|
-
if controlnet is not None:
|
|
137
|
-
from diffusers import ControlNetModel
|
|
138
|
-
|
|
139
|
-
logger.debug("Loading controlnet %s", controlnet)
|
|
140
|
-
self._kwargs["controlnet"] = ControlNetModel.from_pretrained(controlnet)
|
|
141
|
-
|
|
142
|
-
torch_dtype = self._kwargs.get("torch_dtype")
|
|
200
|
+
self._torch_dtype = torch_dtype = self._kwargs.get("torch_dtype")
|
|
143
201
|
if sys.platform != "darwin" and torch_dtype is None:
|
|
144
202
|
# The following params crashes on Mac M2
|
|
145
|
-
self._kwargs["torch_dtype"] = torch.float16
|
|
203
|
+
self._torch_dtype = self._kwargs["torch_dtype"] = torch.float16
|
|
146
204
|
self._kwargs["variant"] = "fp16"
|
|
147
205
|
self._kwargs["use_safetensors"] = True
|
|
148
206
|
if isinstance(torch_dtype, str):
|
|
149
207
|
self._kwargs["torch_dtype"] = getattr(torch, torch_dtype)
|
|
150
208
|
|
|
209
|
+
controlnet = self._kwargs.get("controlnet")
|
|
210
|
+
if controlnet is not None:
|
|
211
|
+
if isinstance(controlnet, tuple):
|
|
212
|
+
self._kwargs["controlnet"] = self._get_controlnet_model(*controlnet)
|
|
213
|
+
else:
|
|
214
|
+
self._kwargs["controlnet"] = [
|
|
215
|
+
self._get_controlnet_model(*cn) for cn in controlnet
|
|
216
|
+
]
|
|
217
|
+
|
|
151
218
|
quantize_text_encoder = self._kwargs.pop("quantize_text_encoder", None)
|
|
152
219
|
if quantize_text_encoder:
|
|
153
220
|
try:
|
|
@@ -193,15 +260,42 @@ class DiffusionModel(SDAPIDiffusionModelMixin):
|
|
|
193
260
|
self._model_path,
|
|
194
261
|
**self._kwargs,
|
|
195
262
|
)
|
|
263
|
+
self._load_to_device(self._model)
|
|
264
|
+
self._apply_lora()
|
|
265
|
+
|
|
266
|
+
if self._kwargs.get("deepcache", False):
|
|
267
|
+
try:
|
|
268
|
+
from DeepCache import DeepCacheSDHelper
|
|
269
|
+
except ImportError:
|
|
270
|
+
error_message = "Failed to import module 'deepcache' when you launch with deepcache=True"
|
|
271
|
+
installation_guide = [
|
|
272
|
+
"Please make sure 'deepcache' is installed. ",
|
|
273
|
+
"You can install it by `pip install deepcache`\n",
|
|
274
|
+
]
|
|
275
|
+
|
|
276
|
+
raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}")
|
|
277
|
+
else:
|
|
278
|
+
self._deepcache_helper = helper = DeepCacheSDHelper()
|
|
279
|
+
helper.set_params(
|
|
280
|
+
cache_interval=self._kwargs.get("deepcache_cache_interval", 3),
|
|
281
|
+
cache_branch_id=self._kwargs.get("deepcache_cache_branch_id", 0),
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
def _load_to_device(self, model):
|
|
196
285
|
if self._kwargs.get("cpu_offload", False):
|
|
197
286
|
logger.debug("CPU offloading model")
|
|
198
|
-
|
|
287
|
+
model.enable_model_cpu_offload()
|
|
288
|
+
elif self._kwargs.get("sequential_cpu_offload", False):
|
|
289
|
+
logger.debug("CPU sequential offloading model")
|
|
290
|
+
model.enable_sequential_cpu_offload()
|
|
199
291
|
elif not self._kwargs.get("device_map"):
|
|
200
292
|
logger.debug("Loading model to available device")
|
|
201
|
-
|
|
293
|
+
model = move_model_to_available_device(self._model)
|
|
202
294
|
# Recommended if your computer has < 64 GB of RAM
|
|
203
|
-
self.
|
|
204
|
-
|
|
295
|
+
if self._kwargs.get("attention_slicing", True):
|
|
296
|
+
model.enable_attention_slicing()
|
|
297
|
+
if self._kwargs.get("vae_tiling", False):
|
|
298
|
+
model.enable_vae_tiling()
|
|
205
299
|
|
|
206
300
|
@staticmethod
|
|
207
301
|
def _get_scheduler(model: Any, sampler_name: str):
|
|
@@ -212,61 +306,78 @@ class DiffusionModel(SDAPIDiffusionModelMixin):
|
|
|
212
306
|
|
|
213
307
|
import diffusers
|
|
214
308
|
|
|
309
|
+
kwargs = {}
|
|
310
|
+
if (
|
|
311
|
+
sampler_name.startswith("DPM++")
|
|
312
|
+
and "final_sigmas_type" not in model.scheduler.config
|
|
313
|
+
):
|
|
314
|
+
# `final_sigmas_type` will be set as `zero` by default which will cause error
|
|
315
|
+
kwargs["final_sigmas_type"] = "sigma_min"
|
|
316
|
+
|
|
215
317
|
# see https://github.com/huggingface/diffusers/issues/4167
|
|
216
318
|
# to get A1111 <> Diffusers Scheduler mapping
|
|
217
319
|
if sampler_name == "DPM++ 2M":
|
|
218
320
|
return diffusers.DPMSolverMultistepScheduler.from_config(
|
|
219
|
-
model.scheduler.config
|
|
321
|
+
model.scheduler.config, **kwargs
|
|
220
322
|
)
|
|
221
323
|
elif sampler_name == "DPM++ 2M Karras":
|
|
222
324
|
return diffusers.DPMSolverMultistepScheduler.from_config(
|
|
223
|
-
model.scheduler.config, use_karras_sigmas=True
|
|
325
|
+
model.scheduler.config, use_karras_sigmas=True, **kwargs
|
|
224
326
|
)
|
|
225
327
|
elif sampler_name == "DPM++ 2M SDE":
|
|
226
328
|
return diffusers.DPMSolverMultistepScheduler.from_config(
|
|
227
|
-
model.scheduler.config, algorithm_type="sde-dpmsolver++"
|
|
329
|
+
model.scheduler.config, algorithm_type="sde-dpmsolver++", **kwargs
|
|
228
330
|
)
|
|
229
331
|
elif sampler_name == "DPM++ 2M SDE Karras":
|
|
230
332
|
return diffusers.DPMSolverMultistepScheduler.from_config(
|
|
231
333
|
model.scheduler.config,
|
|
232
334
|
algorithm_type="sde-dpmsolver++",
|
|
233
335
|
use_karras_sigmas=True,
|
|
336
|
+
**kwargs,
|
|
234
337
|
)
|
|
235
338
|
elif sampler_name == "DPM++ SDE":
|
|
236
339
|
return diffusers.DPMSolverSinglestepScheduler.from_config(
|
|
237
|
-
model.scheduler.config
|
|
340
|
+
model.scheduler.config, **kwargs
|
|
238
341
|
)
|
|
239
342
|
elif sampler_name == "DPM++ SDE Karras":
|
|
240
343
|
return diffusers.DPMSolverSinglestepScheduler.from_config(
|
|
241
|
-
model.scheduler.config, use_karras_sigmas=True
|
|
344
|
+
model.scheduler.config, use_karras_sigmas=True, **kwargs
|
|
242
345
|
)
|
|
243
346
|
elif sampler_name == "DPM2":
|
|
244
|
-
return diffusers.KDPM2DiscreteScheduler.from_config(
|
|
347
|
+
return diffusers.KDPM2DiscreteScheduler.from_config(
|
|
348
|
+
model.scheduler.config, **kwargs
|
|
349
|
+
)
|
|
245
350
|
elif sampler_name == "DPM2 Karras":
|
|
246
351
|
return diffusers.KDPM2DiscreteScheduler.from_config(
|
|
247
|
-
model.scheduler.config, use_karras_sigmas=True
|
|
352
|
+
model.scheduler.config, use_karras_sigmas=True, **kwargs
|
|
248
353
|
)
|
|
249
354
|
elif sampler_name == "DPM2 a":
|
|
250
355
|
return diffusers.KDPM2AncestralDiscreteScheduler.from_config(
|
|
251
|
-
model.scheduler.config
|
|
356
|
+
model.scheduler.config, **kwargs
|
|
252
357
|
)
|
|
253
358
|
elif sampler_name == "DPM2 a Karras":
|
|
254
359
|
return diffusers.KDPM2AncestralDiscreteScheduler.from_config(
|
|
255
|
-
model.scheduler.config, use_karras_sigmas=True
|
|
360
|
+
model.scheduler.config, use_karras_sigmas=True, **kwargs
|
|
256
361
|
)
|
|
257
362
|
elif sampler_name == "Euler":
|
|
258
|
-
return diffusers.EulerDiscreteScheduler.from_config(
|
|
363
|
+
return diffusers.EulerDiscreteScheduler.from_config(
|
|
364
|
+
model.scheduler.config, **kwargs
|
|
365
|
+
)
|
|
259
366
|
elif sampler_name == "Euler a":
|
|
260
367
|
return diffusers.EulerAncestralDiscreteScheduler.from_config(
|
|
261
|
-
model.scheduler.config
|
|
368
|
+
model.scheduler.config, **kwargs
|
|
262
369
|
)
|
|
263
370
|
elif sampler_name == "Heun":
|
|
264
|
-
return diffusers.HeunDiscreteScheduler.from_config(
|
|
371
|
+
return diffusers.HeunDiscreteScheduler.from_config(
|
|
372
|
+
model.scheduler.config, **kwargs
|
|
373
|
+
)
|
|
265
374
|
elif sampler_name == "LMS":
|
|
266
|
-
return diffusers.LMSDiscreteScheduler.from_config(
|
|
375
|
+
return diffusers.LMSDiscreteScheduler.from_config(
|
|
376
|
+
model.scheduler.config, **kwargs
|
|
377
|
+
)
|
|
267
378
|
elif sampler_name == "LMS Karras":
|
|
268
379
|
return diffusers.LMSDiscreteScheduler.from_config(
|
|
269
|
-
model.scheduler.config, use_karras_sigmas=True
|
|
380
|
+
model.scheduler.config, use_karras_sigmas=True, **kwargs
|
|
270
381
|
)
|
|
271
382
|
else:
|
|
272
383
|
raise ValueError(f"Unknown sampler: {sampler_name}")
|
|
@@ -286,27 +397,70 @@ class DiffusionModel(SDAPIDiffusionModelMixin):
|
|
|
286
397
|
else:
|
|
287
398
|
yield
|
|
288
399
|
|
|
400
|
+
@staticmethod
|
|
401
|
+
@contextlib.contextmanager
|
|
402
|
+
def _release_after():
|
|
403
|
+
from ....device_utils import empty_cache
|
|
404
|
+
|
|
405
|
+
try:
|
|
406
|
+
yield
|
|
407
|
+
finally:
|
|
408
|
+
gc.collect()
|
|
409
|
+
empty_cache()
|
|
410
|
+
|
|
411
|
+
@contextlib.contextmanager
|
|
412
|
+
def _wrap_deepcache(self, model: Any):
|
|
413
|
+
if self._deepcache_helper:
|
|
414
|
+
self._deepcache_helper.pipe = model
|
|
415
|
+
self._deepcache_helper.enable()
|
|
416
|
+
try:
|
|
417
|
+
yield
|
|
418
|
+
finally:
|
|
419
|
+
if self._deepcache_helper:
|
|
420
|
+
self._deepcache_helper.disable()
|
|
421
|
+
self._deepcache_helper.pipe = None
|
|
422
|
+
|
|
423
|
+
@staticmethod
|
|
424
|
+
def _process_progressor(kwargs: dict):
|
|
425
|
+
import diffusers
|
|
426
|
+
|
|
427
|
+
progressor: Progressor = kwargs.pop("progressor", None)
|
|
428
|
+
|
|
429
|
+
def report_status_callback(
|
|
430
|
+
pipe: diffusers.DiffusionPipeline,
|
|
431
|
+
step: int,
|
|
432
|
+
timestep: int,
|
|
433
|
+
callback_kwargs: dict,
|
|
434
|
+
):
|
|
435
|
+
num_steps = pipe.num_timesteps
|
|
436
|
+
progressor.set_progress((step + 1) / num_steps)
|
|
437
|
+
|
|
438
|
+
return callback_kwargs
|
|
439
|
+
|
|
440
|
+
if progressor and progressor.request_id:
|
|
441
|
+
kwargs["callback_on_step_end"] = report_status_callback
|
|
442
|
+
|
|
289
443
|
def _call_model(
|
|
290
444
|
self,
|
|
291
445
|
response_format: str,
|
|
292
446
|
model=None,
|
|
293
447
|
**kwargs,
|
|
294
448
|
):
|
|
295
|
-
import gc
|
|
296
|
-
|
|
297
|
-
from ....device_utils import empty_cache
|
|
298
|
-
|
|
299
449
|
model = model if model is not None else self._model
|
|
300
450
|
is_padded = kwargs.pop("is_padded", None)
|
|
301
451
|
origin_size = kwargs.pop("origin_size", None)
|
|
302
452
|
seed = kwargs.pop("seed", None)
|
|
303
|
-
|
|
453
|
+
return_images = kwargs.pop("_return_images", None)
|
|
454
|
+
if seed is not None and seed != -1:
|
|
304
455
|
kwargs["generator"] = generator = torch.Generator(device=get_available_device()) # type: ignore
|
|
305
456
|
if seed != -1:
|
|
306
457
|
kwargs["generator"] = generator.manual_seed(seed)
|
|
307
458
|
sampler_name = kwargs.pop("sampler_name", None)
|
|
459
|
+
self._process_progressor(kwargs)
|
|
308
460
|
assert callable(model)
|
|
309
|
-
with self._reset_when_done(
|
|
461
|
+
with self._reset_when_done(
|
|
462
|
+
model, sampler_name
|
|
463
|
+
), self._release_after(), self._wrap_deepcache(model):
|
|
310
464
|
logger.debug("stable diffusion args: %s, model: %s", kwargs, model)
|
|
311
465
|
self._filter_kwargs(model, kwargs)
|
|
312
466
|
images = model(**kwargs).images
|
|
@@ -319,9 +473,8 @@ class DiffusionModel(SDAPIDiffusionModelMixin):
|
|
|
319
473
|
new_images.append(img.crop((0, 0, x, y)))
|
|
320
474
|
images = new_images
|
|
321
475
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
empty_cache()
|
|
476
|
+
if return_images:
|
|
477
|
+
return images
|
|
325
478
|
|
|
326
479
|
if response_format == "url":
|
|
327
480
|
os.makedirs(XINFERENCE_IMAGE_DIR, exist_ok=True)
|
|
@@ -366,15 +519,13 @@ class DiffusionModel(SDAPIDiffusionModelMixin):
|
|
|
366
519
|
response_format: str = "url",
|
|
367
520
|
**kwargs,
|
|
368
521
|
):
|
|
369
|
-
# References:
|
|
370
|
-
# https://huggingface.co/docs/diffusers/main/en/api/pipelines/controlnet_sdxl
|
|
371
522
|
width, height = map(int, re.split(r"[^\d]+", size))
|
|
372
523
|
generate_kwargs = self._model_spec.default_generate_config.copy() # type: ignore
|
|
373
524
|
generate_kwargs.update({k: v for k, v in kwargs.items() if v is not None})
|
|
525
|
+
generate_kwargs["width"], generate_kwargs["height"] = width, height
|
|
526
|
+
|
|
374
527
|
return self._call_model(
|
|
375
528
|
prompt=prompt,
|
|
376
|
-
height=height,
|
|
377
|
-
width=width,
|
|
378
529
|
num_images_per_prompt=n,
|
|
379
530
|
response_format=response_format,
|
|
380
531
|
**generate_kwargs,
|
|
@@ -397,19 +548,13 @@ class DiffusionModel(SDAPIDiffusionModelMixin):
|
|
|
397
548
|
response_format: str = "url",
|
|
398
549
|
**kwargs,
|
|
399
550
|
):
|
|
400
|
-
if "controlnet"
|
|
551
|
+
if self._kwargs.get("controlnet"):
|
|
401
552
|
model = self._model
|
|
402
553
|
else:
|
|
403
|
-
|
|
554
|
+
ability = "image2image"
|
|
555
|
+
if ability not in self._abilities:
|
|
404
556
|
raise RuntimeError(f"{self._model_uid} does not support image2image")
|
|
405
|
-
|
|
406
|
-
model = self._i2i_model
|
|
407
|
-
else:
|
|
408
|
-
from diffusers import AutoPipelineForImage2Image
|
|
409
|
-
|
|
410
|
-
self._i2i_model = model = AutoPipelineForImage2Image.from_pipe(
|
|
411
|
-
self._model
|
|
412
|
-
)
|
|
557
|
+
model = self._get_model(ability)
|
|
413
558
|
|
|
414
559
|
if padding_image_to_multiple := kwargs.pop("padding_image_to_multiple", None):
|
|
415
560
|
# Model like SD3 image to image requires image's height and width is times of 16
|
|
@@ -450,24 +595,23 @@ class DiffusionModel(SDAPIDiffusionModelMixin):
|
|
|
450
595
|
response_format: str = "url",
|
|
451
596
|
**kwargs,
|
|
452
597
|
):
|
|
453
|
-
|
|
598
|
+
ability = "inpainting"
|
|
599
|
+
if ability not in self._abilities:
|
|
454
600
|
raise RuntimeError(f"{self._model_uid} does not support inpainting")
|
|
455
601
|
|
|
456
602
|
if (
|
|
457
603
|
"text2image" in self._abilities or "image2image" in self._abilities
|
|
458
604
|
) and self._model is not None:
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
if self._inpainting_model is not None:
|
|
462
|
-
model = self._inpainting_model
|
|
463
|
-
else:
|
|
464
|
-
model = self._inpainting_model = AutoPipelineForInpainting.from_pipe(
|
|
465
|
-
self._model
|
|
466
|
-
)
|
|
605
|
+
model = self._get_model(ability)
|
|
467
606
|
else:
|
|
468
607
|
model = self._model
|
|
469
608
|
|
|
470
|
-
|
|
609
|
+
if mask_blur := kwargs.pop("mask_blur", None):
|
|
610
|
+
logger.debug("Process mask image with mask_blur: %s", mask_blur)
|
|
611
|
+
mask_image = model.mask_processor.blur(mask_image, blur_factor=mask_blur) # type: ignore
|
|
612
|
+
|
|
613
|
+
if "width" not in kwargs:
|
|
614
|
+
kwargs["width"], kwargs["height"] = map(int, re.split(r"[^\d]+", size))
|
|
471
615
|
|
|
472
616
|
if padding_image_to_multiple := kwargs.pop("padding_image_to_multiple", None):
|
|
473
617
|
# Model like SD3 inpainting requires image's height and width is times of 16
|
|
@@ -480,14 +624,12 @@ class DiffusionModel(SDAPIDiffusionModelMixin):
|
|
|
480
624
|
mask_image, multiple=int(padding_image_to_multiple)
|
|
481
625
|
)
|
|
482
626
|
# calculate actual image size after padding
|
|
483
|
-
width, height = image.size
|
|
627
|
+
kwargs["width"], kwargs["height"] = image.size
|
|
484
628
|
|
|
485
629
|
return self._call_model(
|
|
486
630
|
image=image,
|
|
487
631
|
mask_image=mask_image,
|
|
488
632
|
prompt=prompt,
|
|
489
|
-
height=height,
|
|
490
|
-
width=width,
|
|
491
633
|
num_images_per_prompt=n,
|
|
492
634
|
response_format=response_format,
|
|
493
635
|
model=model,
|