xinference 1.10.1__py3-none-any.whl → 1.11.0__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.

Files changed (38) hide show
  1. xinference/_version.py +3 -3
  2. xinference/api/restful_api.py +462 -3
  3. xinference/client/restful/async_restful_client.py +158 -5
  4. xinference/client/restful/restful_client.py +131 -0
  5. xinference/core/supervisor.py +12 -0
  6. xinference/model/audio/model_spec.json +20 -20
  7. xinference/model/image/model_spec.json +159 -159
  8. xinference/model/llm/__init__.py +2 -2
  9. xinference/model/llm/llm_family.json +843 -180
  10. xinference/model/llm/mlx/distributed_models/core.py +41 -0
  11. xinference/model/llm/mlx/distributed_models/qwen2.py +1 -2
  12. xinference/model/llm/sglang/core.py +20 -6
  13. xinference/model/llm/tool_parsers/qwen_tool_parser.py +29 -4
  14. xinference/model/llm/transformers/chatglm.py +3 -0
  15. xinference/model/llm/transformers/core.py +129 -36
  16. xinference/model/llm/transformers/multimodal/minicpmv45.py +340 -0
  17. xinference/model/llm/transformers/utils.py +23 -0
  18. xinference/model/llm/utils.py +37 -24
  19. xinference/model/llm/vllm/core.py +128 -69
  20. xinference/model/utils.py +74 -31
  21. xinference/thirdparty/audiotools/core/audio_signal.py +6 -6
  22. xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/text.py +1 -1
  23. xinference/thirdparty/melo/text/chinese_mix.py +2 -2
  24. xinference/types.py +9 -0
  25. xinference/ui/web/ui/build/asset-manifest.json +3 -3
  26. xinference/ui/web/ui/build/index.html +1 -1
  27. xinference/ui/web/ui/build/static/js/{main.d192c4f3.js → main.45e78536.js} +3 -3
  28. xinference/ui/web/ui/build/static/js/main.45e78536.js.map +1 -0
  29. xinference/ui/web/ui/node_modules/.cache/babel-loader/ea2a26361204e70cf1018d6990fb6354bed82b3ac69690391e0f100385e7abb7.json +1 -0
  30. {xinference-1.10.1.dist-info → xinference-1.11.0.dist-info}/METADATA +7 -5
  31. {xinference-1.10.1.dist-info → xinference-1.11.0.dist-info}/RECORD +36 -35
  32. xinference/ui/web/ui/build/static/js/main.d192c4f3.js.map +0 -1
  33. xinference/ui/web/ui/node_modules/.cache/babel-loader/f995a2425dfb0822fd07127f66ffe9b026883bc156b402eb8bd0b83d52460a93.json +0 -1
  34. /xinference/ui/web/ui/build/static/js/{main.d192c4f3.js.LICENSE.txt → main.45e78536.js.LICENSE.txt} +0 -0
  35. {xinference-1.10.1.dist-info → xinference-1.11.0.dist-info}/WHEEL +0 -0
  36. {xinference-1.10.1.dist-info → xinference-1.11.0.dist-info}/entry_points.txt +0 -0
  37. {xinference-1.10.1.dist-info → xinference-1.11.0.dist-info}/licenses/LICENSE +0 -0
  38. {xinference-1.10.1.dist-info → xinference-1.11.0.dist-info}/top_level.txt +0 -0
@@ -74,6 +74,7 @@ class AsyncRESTfulModelHandle:
74
74
  self._model_uid = model_uid
75
75
  self._base_url = base_url
76
76
  self.auth_headers = auth_headers
77
+ self.timeout = aiohttp.ClientTimeout(total=1800)
77
78
  self.session = aiohttp.ClientSession(
78
79
  connector=aiohttp.TCPConnector(force_close=True)
79
80
  )
@@ -356,7 +357,7 @@ class AsyncRESTfulImageModelHandle(AsyncRESTfulModelHandle):
356
357
  else:
357
358
  # Single image
358
359
  files.append(("image", ("image", image, "application/octet-stream")))
359
- response = await self.session.post(url, files=files, headers=self.auth_headers)
360
+ response = await self.session.post(url, data=files, headers=self.auth_headers)
360
361
  if response.status != 200:
361
362
  raise RuntimeError(
362
363
  f"Failed to variants the images, detail: {await _get_error_string(response)}"
@@ -366,6 +367,157 @@ class AsyncRESTfulImageModelHandle(AsyncRESTfulModelHandle):
366
367
  await _release_response(response)
367
368
  return response_data
368
369
 
370
+ async def image_edit(
371
+ self,
372
+ image: Union[Union[str, bytes], List[Union[str, bytes]]],
373
+ prompt: str,
374
+ mask: Optional[Union[str, bytes]] = None,
375
+ n: int = 1,
376
+ size: Optional[str] = None,
377
+ response_format: str = "url",
378
+ **kwargs,
379
+ ) -> "ImageList":
380
+ """
381
+ Edit image(s) by the input text and optional mask.
382
+
383
+ Parameters
384
+ ----------
385
+ image: `Union[Union[str, bytes], List[Union[str, bytes]]]`
386
+ The input image(s) to edit. Can be:
387
+ - Single image: file path, URL, or binary image data
388
+ - Multiple images: list of file paths, URLs, or binary image data
389
+ When multiple images are provided, the first image is used as the primary image
390
+ and subsequent images are used as reference images for better editing results.
391
+ prompt: `str`
392
+ The prompt or prompts to guide image editing. If not defined, you need to pass `prompt_embeds`.
393
+ mask: `Optional[Union[str, bytes]]`, optional
394
+ An optional mask image. White pixels in the mask are repainted while black pixels are preserved.
395
+ If provided, this will trigger inpainting mode. If not provided, this will trigger image-to-image mode.
396
+ n: `int`, defaults to 1
397
+ The number of images to generate per prompt. Must be between 1 and 10.
398
+ size: `Optional[str]`, optional
399
+ The width*height in pixels of the generated image. If not specified, uses the original image size.
400
+ response_format: `str`, defaults to `url`
401
+ The format in which the generated images are returned. Must be one of url or b64_json.
402
+ **kwargs
403
+ Additional parameters to pass to the model.
404
+
405
+ Returns
406
+ -------
407
+ ImageList
408
+ A list of edited image objects.
409
+
410
+ Raises
411
+ ------
412
+ RuntimeError
413
+ If the image editing request fails.
414
+
415
+ Examples
416
+ --------
417
+ # Single image editing
418
+ result = await model.image_edit(
419
+ image="path/to/image.png",
420
+ prompt="make this image look like a painting"
421
+ )
422
+
423
+ # Multiple image editing with reference images
424
+ result = await model.image_edit(
425
+ image=["primary_image.png", "reference1.jpg", "reference2.png"],
426
+ prompt="edit the main image using the style from reference images"
427
+ )
428
+ """
429
+ url = f"{self._base_url}/v1/images/edits"
430
+ params = {
431
+ "model": self._model_uid,
432
+ "prompt": prompt,
433
+ "n": n,
434
+ "size": size,
435
+ "response_format": response_format,
436
+ "kwargs": json.dumps(kwargs),
437
+ }
438
+ params = _filter_params(params)
439
+ files: List[Any] = []
440
+ for key, value in params.items():
441
+ files.append((key, (None, value)))
442
+
443
+ # Handle single image or multiple images
444
+ import aiohttp
445
+
446
+ data = aiohttp.FormData()
447
+
448
+ # Add all parameters as form fields
449
+ for key, value in params.items():
450
+ if value is not None:
451
+ data.add_field(key, str(value))
452
+
453
+ # Handle single image or multiple images
454
+ if isinstance(image, list):
455
+ # Validate image list is not empty
456
+ if len(image) == 0:
457
+ raise ValueError("Image list cannot be empty")
458
+ # Multiple images - send as image[] array
459
+ for i, img in enumerate(image):
460
+ if isinstance(img, str):
461
+ # File path - read file content
462
+ with open(img, "rb") as f:
463
+ content = f.read()
464
+ data.add_field(
465
+ f"image[]",
466
+ content,
467
+ filename=f"image_{i}.png",
468
+ content_type="image/png",
469
+ )
470
+ else:
471
+ # Binary data
472
+ data.add_field(
473
+ f"image[]",
474
+ img,
475
+ filename=f"image_{i}.png",
476
+ content_type="image/png",
477
+ )
478
+ else:
479
+ # Single image
480
+ if isinstance(image, str):
481
+ # File path - read file content
482
+ with open(image, "rb") as f:
483
+ content = f.read()
484
+ data.add_field(
485
+ "image", content, filename="image.png", content_type="image/png"
486
+ )
487
+ else:
488
+ # Binary data
489
+ data.add_field(
490
+ "image", image, filename="image.png", content_type="image/png"
491
+ )
492
+
493
+ if mask is not None:
494
+ if isinstance(mask, str):
495
+ # File path - read file content
496
+ with open(mask, "rb") as f:
497
+ content = f.read()
498
+ data.add_field(
499
+ "mask", content, filename="mask.png", content_type="image/png"
500
+ )
501
+ else:
502
+ # Binary data
503
+ data.add_field(
504
+ "mask", mask, filename="mask.png", content_type="image/png"
505
+ )
506
+
507
+ try:
508
+ response = await self.session.post(
509
+ url, data=data, headers=self.auth_headers
510
+ )
511
+ if response.status != 200:
512
+ raise RuntimeError(
513
+ f"Failed to edit the images, detail: {await _get_error_string(response)}"
514
+ )
515
+
516
+ response_data = await response.json()
517
+ return response_data
518
+ finally:
519
+ await _release_response(response) if "response" in locals() else None
520
+
369
521
  async def inpainting(
370
522
  self,
371
523
  image: Union[str, bytes],
@@ -436,7 +588,7 @@ class AsyncRESTfulImageModelHandle(AsyncRESTfulModelHandle):
436
588
  ("mask_image", mask_image, "application/octet-stream"),
437
589
  )
438
590
  )
439
- response = await self.session.post(url, files=files, headers=self.auth_headers)
591
+ response = await self.session.post(url, data=files, headers=self.auth_headers)
440
592
  if response.status != 200:
441
593
  raise RuntimeError(
442
594
  f"Failed to inpaint the images, detail: {await _get_error_string(response)}"
@@ -457,7 +609,7 @@ class AsyncRESTfulImageModelHandle(AsyncRESTfulModelHandle):
457
609
  for key, value in params.items():
458
610
  files.append((key, (None, value)))
459
611
  files.append(("image", ("image", image, "application/octet-stream")))
460
- response = await self.session.post(url, files=files, headers=self.auth_headers)
612
+ response = await self.session.post(url, data=files, headers=self.auth_headers)
461
613
  if response.status != 200:
462
614
  raise RuntimeError(
463
615
  f"Failed to ocr the images, detail: {await _get_error_string(response)}"
@@ -547,7 +699,7 @@ class AsyncRESTfulVideoModelHandle(AsyncRESTfulModelHandle):
547
699
  for key, value in params.items():
548
700
  files.append((key, (None, value)))
549
701
  files.append(("image", ("image", image, "application/octet-stream")))
550
- response = await self.session.post(url, files=files, headers=self.auth_headers)
702
+ response = await self.session.post(url, data=files, headers=self.auth_headers)
551
703
  if response.status != 200:
552
704
  raise RuntimeError(
553
705
  f"Failed to create the video from image, detail: {await _get_error_string(response)}"
@@ -987,8 +1139,9 @@ class AsyncClient:
987
1139
  self.base_url = base_url
988
1140
  self._headers: Dict[str, str] = {}
989
1141
  self._cluster_authed = False
1142
+ self.timeout = aiohttp.ClientTimeout(total=1800)
990
1143
  self.session = aiohttp.ClientSession(
991
- connector=aiohttp.TCPConnector(force_close=True)
1144
+ connector=aiohttp.TCPConnector(force_close=True), timeout=self.timeout
992
1145
  )
993
1146
  self._check_cluster_authenticated()
994
1147
  if api_key is not None and self._cluster_authed:
@@ -329,6 +329,137 @@ class RESTfulImageModelHandle(RESTfulModelHandle):
329
329
  response_data = response.json()
330
330
  return response_data
331
331
 
332
+ def image_edit(
333
+ self,
334
+ image: Union[Union[str, bytes], List[Union[str, bytes]]],
335
+ prompt: str,
336
+ mask: Optional[Union[str, bytes]] = None,
337
+ n: int = 1,
338
+ size: Optional[str] = None,
339
+ response_format: str = "url",
340
+ **kwargs,
341
+ ) -> "ImageList":
342
+ """
343
+ Edit image(s) by the input text and optional mask.
344
+
345
+ Parameters
346
+ ----------
347
+ image: `Union[Union[str, bytes], List[Union[str, bytes]]]`
348
+ The input image(s) to edit. Can be:
349
+ - Single image: file path, URL, or binary image data
350
+ - Multiple images: list of file paths, URLs, or binary image data
351
+ When multiple images are provided, the first image is used as the primary image
352
+ and subsequent images are used as reference images for better editing results.
353
+ prompt: `str`
354
+ The prompt or prompts to guide image editing. If not defined, you need to pass `prompt_embeds`.
355
+ mask: `Optional[Union[str, bytes]]`, optional
356
+ An optional mask image. White pixels in the mask are repainted while black pixels are preserved.
357
+ If provided, this will trigger inpainting mode. If not provided, this will trigger image-to-image mode.
358
+ n: `int`, defaults to 1
359
+ The number of images to generate per prompt. Must be between 1 and 10.
360
+ size: `Optional[str]`, optional
361
+ The width*height in pixels of the generated image. If not specified, uses the original image size.
362
+ response_format: `str`, defaults to `url`
363
+ The format in which the generated images are returned. Must be one of url or b64_json.
364
+ **kwargs
365
+ Additional parameters to pass to the model.
366
+
367
+ Returns
368
+ -------
369
+ ImageList
370
+ A list of edited image objects.
371
+
372
+ Raises
373
+ ------
374
+ RuntimeError
375
+ If the image editing request fails.
376
+
377
+ Examples
378
+ --------
379
+ # Single image editing
380
+ result = model.image_edit(
381
+ image="path/to/image.png",
382
+ prompt="make this image look like a painting"
383
+ )
384
+
385
+ # Multiple image editing with reference images
386
+ result = model.image_edit(
387
+ image=["primary_image.png", "reference1.jpg", "reference2.png"],
388
+ prompt="edit the main image using the style from reference images"
389
+ )
390
+ """
391
+ url = f"{self._base_url}/v1/images/edits"
392
+ params = {
393
+ "model": self._model_uid,
394
+ "prompt": prompt,
395
+ "n": n,
396
+ "size": size,
397
+ "response_format": response_format,
398
+ "kwargs": json.dumps(kwargs),
399
+ }
400
+ files: List[Any] = []
401
+ for key, value in params.items():
402
+ if value is not None:
403
+ files.append((key, (None, value)))
404
+
405
+ # Handle single image or multiple images using requests format
406
+ if isinstance(image, list):
407
+ # Validate image list is not empty
408
+ if len(image) == 0:
409
+ raise ValueError("Image list cannot be empty")
410
+ # Multiple images - send as image[] array
411
+ for i, img in enumerate(image):
412
+ if isinstance(img, str):
413
+ # File path - open file
414
+ f = open(img, "rb")
415
+ files.append(
416
+ (f"image[]", (f"image_{i}", f, "application/octet-stream"))
417
+ )
418
+ else:
419
+ # Binary data
420
+ files.append(
421
+ (f"image[]", (f"image_{i}", img, "application/octet-stream"))
422
+ )
423
+ else:
424
+ # Single image
425
+ if isinstance(image, str):
426
+ # File path - open file
427
+ f = open(image, "rb")
428
+ files.append(("image", ("image", f, "application/octet-stream")))
429
+ else:
430
+ # Binary data
431
+ files.append(("image", ("image", image, "application/octet-stream")))
432
+
433
+ if mask is not None:
434
+ if isinstance(mask, str):
435
+ # File path - open file
436
+ f = open(mask, "rb")
437
+ files.append(("mask", ("mask", f, "application/octet-stream")))
438
+ else:
439
+ # Binary data
440
+ files.append(("mask", ("mask", mask, "application/octet-stream")))
441
+
442
+ try:
443
+ response = self.session.post(url, files=files, headers=self.auth_headers)
444
+ if response.status_code != 200:
445
+ raise RuntimeError(
446
+ f"Failed to edit the images, detail: {_get_error_string(response)}"
447
+ )
448
+
449
+ response_data = response.json()
450
+ return response_data
451
+ finally:
452
+ # Close all opened files
453
+ for file_item in files:
454
+ if (
455
+ len(file_item) >= 2
456
+ and hasattr(file_item[1], "__len__")
457
+ and len(file_item[1]) >= 2
458
+ ):
459
+ file_obj = file_item[1][1]
460
+ if hasattr(file_obj, "close"):
461
+ file_obj.close()
462
+
332
463
  def inpainting(
333
464
  self,
334
465
  image: Union[str, bytes],
@@ -1661,6 +1661,9 @@ class SupervisorActor(xo.StatelessActor):
1661
1661
  if isinstance(worker_ref, list):
1662
1662
  # get first worker to fetch information if model across workers
1663
1663
  worker_ref = worker_ref[0]
1664
+ assert not isinstance(
1665
+ worker_ref, (list, tuple)
1666
+ ), "worker_ref must be a single worker"
1664
1667
  return await worker_ref.get_model(model_uid=replica_model_uid)
1665
1668
 
1666
1669
  @log_async(logger=logger)
@@ -1673,6 +1676,9 @@ class SupervisorActor(xo.StatelessActor):
1673
1676
  if isinstance(worker_ref, list):
1674
1677
  # get status from first shard if model has multiple shards across workers
1675
1678
  worker_ref = worker_ref[0]
1679
+ assert not isinstance(
1680
+ worker_ref, (list, tuple)
1681
+ ), "worker_ref must be a single worker"
1676
1682
  return await worker_ref.get_model_status(replica_model_uid)
1677
1683
 
1678
1684
  @log_async(logger=logger)
@@ -1691,6 +1697,9 @@ class SupervisorActor(xo.StatelessActor):
1691
1697
  if isinstance(worker_ref, list):
1692
1698
  # get status from first shard if model has multiple shards across workers
1693
1699
  worker_ref = worker_ref[0]
1700
+ assert not isinstance(
1701
+ worker_ref, (list, tuple)
1702
+ ), "worker_ref must be a single worker"
1694
1703
  info = await worker_ref.describe_model(model_uid=replica_model_uid)
1695
1704
  info["replica"] = replica_info.replica
1696
1705
  return info
@@ -1766,6 +1775,9 @@ class SupervisorActor(xo.StatelessActor):
1766
1775
  if isinstance(worker_ref, list):
1767
1776
  # get status from first shard if model has multiple shards across workers
1768
1777
  worker_ref = worker_ref[0]
1778
+ assert not isinstance(
1779
+ worker_ref, (list, tuple)
1780
+ ), "worker_ref must be a single worker"
1769
1781
  model_ref = await worker_ref.get_model(model_uid=rep_mid)
1770
1782
  result_info = await model_ref.abort_request(request_id, block_duration)
1771
1783
  res["msg"] = result_info
@@ -862,26 +862,6 @@
862
862
  "model_revision": "master"
863
863
  }
864
864
  }
865
- },
866
- {
867
- "version": 2,
868
- "model_name": "Kokoro-82M-v1.1-zh",
869
- "model_family": "Kokoro-zh",
870
- "model_ability": [
871
- "text2audio",
872
- "text2audio_zero_shot"
873
- ],
874
- "multilingual": false,
875
- "model_src": {
876
- "huggingface": {
877
- "model_id": "hexgrad/Kokoro-82M-v1.1-zh",
878
- "model_revision": "01e7505bd6a7a2ac4975463114c3a7650a9f7218"
879
- },
880
- "modelscope": {
881
- "model_id": "AI-ModelScope/Kokoro-82M-v1.1-zh",
882
- "model_revision": "master"
883
- }
884
- }
885
865
  },
886
866
  {
887
867
  "version": 2,
@@ -932,6 +912,26 @@
932
912
  }
933
913
  }
934
914
  },
915
+ {
916
+ "version": 2,
917
+ "model_name": "Kokoro-82M-v1.1-zh",
918
+ "model_family": "Kokoro-zh",
919
+ "model_ability": [
920
+ "text2audio",
921
+ "text2audio_zero_shot"
922
+ ],
923
+ "multilingual": false,
924
+ "model_src": {
925
+ "huggingface": {
926
+ "model_id": "hexgrad/Kokoro-82M-v1.1-zh",
927
+ "model_revision": "01e7505bd6a7a2ac4975463114c3a7650a9f7218"
928
+ },
929
+ "modelscope": {
930
+ "model_id": "AI-ModelScope/Kokoro-82M-v1.1-zh",
931
+ "model_revision": "master"
932
+ }
933
+ }
934
+ },
935
935
  {
936
936
  "version": 2,
937
937
  "model_name": "IndexTTS2",