clarifai 11.1.5rc7__py3-none-any.whl → 11.1.6__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.
Files changed (122) hide show
  1. clarifai/__init__.py +1 -1
  2. clarifai/cli/model.py +40 -50
  3. clarifai/client/model.py +365 -95
  4. clarifai/runners/__init__.py +7 -2
  5. clarifai/runners/dockerfile_template/Dockerfile.template +1 -4
  6. clarifai/runners/models/base_typed_model.py +238 -0
  7. clarifai/runners/models/model_builder.py +9 -26
  8. clarifai/runners/models/model_class.py +28 -273
  9. clarifai/runners/models/model_run_locally.py +78 -3
  10. clarifai/runners/models/model_runner.py +0 -2
  11. clarifai/runners/models/model_servicer.py +2 -11
  12. clarifai/runners/utils/data_handler.py +205 -308
  13. {clarifai-11.1.5rc7.dist-info → clarifai-11.1.6.dist-info}/METADATA +26 -16
  14. clarifai-11.1.6.dist-info/RECORD +101 -0
  15. {clarifai-11.1.5rc7.dist-info → clarifai-11.1.6.dist-info}/WHEEL +1 -1
  16. clarifai/__pycache__/__init__.cpython-310.pyc +0 -0
  17. clarifai/__pycache__/errors.cpython-310.pyc +0 -0
  18. clarifai/__pycache__/versions.cpython-310.pyc +0 -0
  19. clarifai/cli/__main__.py~ +0 -4
  20. clarifai/cli/__pycache__/__init__.cpython-310.pyc +0 -0
  21. clarifai/cli/__pycache__/__main__.cpython-310.pyc +0 -0
  22. clarifai/cli/__pycache__/base.cpython-310.pyc +0 -0
  23. clarifai/cli/__pycache__/compute_cluster.cpython-310.pyc +0 -0
  24. clarifai/cli/__pycache__/deployment.cpython-310.pyc +0 -0
  25. clarifai/cli/__pycache__/model.cpython-310.pyc +0 -0
  26. clarifai/cli/__pycache__/nodepool.cpython-310.pyc +0 -0
  27. clarifai/client/__pycache__/__init__.cpython-310.pyc +0 -0
  28. clarifai/client/__pycache__/app.cpython-310.pyc +0 -0
  29. clarifai/client/__pycache__/base.cpython-310.pyc +0 -0
  30. clarifai/client/__pycache__/dataset.cpython-310.pyc +0 -0
  31. clarifai/client/__pycache__/input.cpython-310.pyc +0 -0
  32. clarifai/client/__pycache__/lister.cpython-310.pyc +0 -0
  33. clarifai/client/__pycache__/model.cpython-310.pyc +0 -0
  34. clarifai/client/__pycache__/module.cpython-310.pyc +0 -0
  35. clarifai/client/__pycache__/runner.cpython-310.pyc +0 -0
  36. clarifai/client/__pycache__/search.cpython-310.pyc +0 -0
  37. clarifai/client/__pycache__/user.cpython-310.pyc +0 -0
  38. clarifai/client/__pycache__/workflow.cpython-310.pyc +0 -0
  39. clarifai/client/auth/__pycache__/__init__.cpython-310.pyc +0 -0
  40. clarifai/client/auth/__pycache__/helper.cpython-310.pyc +0 -0
  41. clarifai/client/auth/__pycache__/register.cpython-310.pyc +0 -0
  42. clarifai/client/auth/__pycache__/stub.cpython-310.pyc +0 -0
  43. clarifai/client/model_client.py +0 -432
  44. clarifai/constants/__pycache__/dataset.cpython-310.pyc +0 -0
  45. clarifai/constants/__pycache__/model.cpython-310.pyc +0 -0
  46. clarifai/constants/__pycache__/search.cpython-310.pyc +0 -0
  47. clarifai/datasets/__pycache__/__init__.cpython-310.pyc +0 -0
  48. clarifai/datasets/export/__pycache__/__init__.cpython-310.pyc +0 -0
  49. clarifai/datasets/export/__pycache__/inputs_annotations.cpython-310.pyc +0 -0
  50. clarifai/datasets/upload/__pycache__/__init__.cpython-310.pyc +0 -0
  51. clarifai/datasets/upload/__pycache__/base.cpython-310.pyc +0 -0
  52. clarifai/datasets/upload/__pycache__/features.cpython-310.pyc +0 -0
  53. clarifai/datasets/upload/__pycache__/image.cpython-310.pyc +0 -0
  54. clarifai/datasets/upload/__pycache__/text.cpython-310.pyc +0 -0
  55. clarifai/datasets/upload/__pycache__/utils.cpython-310.pyc +0 -0
  56. clarifai/datasets/upload/loaders/__pycache__/__init__.cpython-310.pyc +0 -0
  57. clarifai/datasets/upload/loaders/__pycache__/coco_detection.cpython-310.pyc +0 -0
  58. clarifai/models/__pycache__/__init__.cpython-310.pyc +0 -0
  59. clarifai/models/model_serving/__pycache__/__init__.cpython-310.pyc +0 -0
  60. clarifai/models/model_serving/__pycache__/constants.cpython-310.pyc +0 -0
  61. clarifai/models/model_serving/cli/__pycache__/__init__.cpython-310.pyc +0 -0
  62. clarifai/models/model_serving/cli/__pycache__/_utils.cpython-310.pyc +0 -0
  63. clarifai/models/model_serving/cli/__pycache__/base.cpython-310.pyc +0 -0
  64. clarifai/models/model_serving/cli/__pycache__/build.cpython-310.pyc +0 -0
  65. clarifai/models/model_serving/cli/__pycache__/create.cpython-310.pyc +0 -0
  66. clarifai/models/model_serving/model_config/__pycache__/__init__.cpython-310.pyc +0 -0
  67. clarifai/models/model_serving/model_config/__pycache__/base.cpython-310.pyc +0 -0
  68. clarifai/models/model_serving/model_config/__pycache__/config.cpython-310.pyc +0 -0
  69. clarifai/models/model_serving/model_config/__pycache__/inference_parameter.cpython-310.pyc +0 -0
  70. clarifai/models/model_serving/model_config/__pycache__/output.cpython-310.pyc +0 -0
  71. clarifai/models/model_serving/model_config/triton/__pycache__/__init__.cpython-310.pyc +0 -0
  72. clarifai/models/model_serving/model_config/triton/__pycache__/serializer.cpython-310.pyc +0 -0
  73. clarifai/models/model_serving/model_config/triton/__pycache__/triton_config.cpython-310.pyc +0 -0
  74. clarifai/models/model_serving/model_config/triton/__pycache__/wrappers.cpython-310.pyc +0 -0
  75. clarifai/models/model_serving/repo_build/__pycache__/__init__.cpython-310.pyc +0 -0
  76. clarifai/models/model_serving/repo_build/__pycache__/build.cpython-310.pyc +0 -0
  77. clarifai/models/model_serving/repo_build/static_files/__pycache__/base_test.cpython-310-pytest-7.2.0.pyc +0 -0
  78. clarifai/rag/__pycache__/__init__.cpython-310.pyc +0 -0
  79. clarifai/rag/__pycache__/rag.cpython-310.pyc +0 -0
  80. clarifai/rag/__pycache__/utils.cpython-310.pyc +0 -0
  81. clarifai/runners/__pycache__/__init__.cpython-310.pyc +0 -0
  82. clarifai/runners/__pycache__/server.cpython-310.pyc +0 -0
  83. clarifai/runners/dockerfile_template/Dockerfile.debug +0 -11
  84. clarifai/runners/dockerfile_template/Dockerfile.debug~ +0 -9
  85. clarifai/runners/models/__pycache__/__init__.cpython-310.pyc +0 -0
  86. clarifai/runners/models/__pycache__/base_typed_model.cpython-310.pyc +0 -0
  87. clarifai/runners/models/__pycache__/model_builder.cpython-310.pyc +0 -0
  88. clarifai/runners/models/__pycache__/model_class.cpython-310.pyc +0 -0
  89. clarifai/runners/models/__pycache__/model_run_locally.cpython-310.pyc +0 -0
  90. clarifai/runners/models/__pycache__/model_runner.cpython-310.pyc +0 -0
  91. clarifai/runners/models/__pycache__/model_servicer.cpython-310.pyc +0 -0
  92. clarifai/runners/models/__pycache__/model_upload.cpython-310.pyc +0 -0
  93. clarifai/runners/utils/__pycache__/__init__.cpython-310.pyc +0 -0
  94. clarifai/runners/utils/__pycache__/const.cpython-310.pyc +0 -0
  95. clarifai/runners/utils/__pycache__/data_handler.cpython-310.pyc +0 -0
  96. clarifai/runners/utils/__pycache__/data_types.cpython-310.pyc +0 -0
  97. clarifai/runners/utils/__pycache__/data_utils.cpython-310.pyc +0 -0
  98. clarifai/runners/utils/__pycache__/loader.cpython-310.pyc +0 -0
  99. clarifai/runners/utils/__pycache__/logging.cpython-310.pyc +0 -0
  100. clarifai/runners/utils/__pycache__/method_signatures.cpython-310.pyc +0 -0
  101. clarifai/runners/utils/__pycache__/serializers.cpython-310.pyc +0 -0
  102. clarifai/runners/utils/__pycache__/url_fetcher.cpython-310.pyc +0 -0
  103. clarifai/runners/utils/data_types.py +0 -334
  104. clarifai/runners/utils/method_signatures.py +0 -452
  105. clarifai/runners/utils/serializers.py +0 -132
  106. clarifai/schema/__pycache__/search.cpython-310.pyc +0 -0
  107. clarifai/urls/__pycache__/helper.cpython-310.pyc +0 -0
  108. clarifai/utils/__pycache__/__init__.cpython-310.pyc +0 -0
  109. clarifai/utils/__pycache__/logging.cpython-310.pyc +0 -0
  110. clarifai/utils/__pycache__/misc.cpython-310.pyc +0 -0
  111. clarifai/utils/__pycache__/model_train.cpython-310.pyc +0 -0
  112. clarifai/utils/evaluation/__pycache__/__init__.cpython-310.pyc +0 -0
  113. clarifai/utils/evaluation/__pycache__/helpers.cpython-310.pyc +0 -0
  114. clarifai/utils/evaluation/__pycache__/main.cpython-310.pyc +0 -0
  115. clarifai/workflows/__pycache__/__init__.cpython-310.pyc +0 -0
  116. clarifai/workflows/__pycache__/export.cpython-310.pyc +0 -0
  117. clarifai/workflows/__pycache__/utils.cpython-310.pyc +0 -0
  118. clarifai/workflows/__pycache__/validate.cpython-310.pyc +0 -0
  119. clarifai-11.1.5rc7.dist-info/RECORD +0 -203
  120. {clarifai-11.1.5rc7.dist-info → clarifai-11.1.6.dist-info}/LICENSE +0 -0
  121. {clarifai-11.1.5rc7.dist-info → clarifai-11.1.6.dist-info}/entry_points.txt +0 -0
  122. {clarifai-11.1.5rc7.dist-info → clarifai-11.1.6.dist-info}/top_level.txt +0 -0
clarifai/client/model.py CHANGED
@@ -7,7 +7,7 @@ import numpy as np
7
7
  import requests
8
8
  import yaml
9
9
  from clarifai_grpc.grpc.api import resources_pb2, service_pb2
10
- from clarifai_grpc.grpc.api.resources_pb2 import Input
10
+ from clarifai_grpc.grpc.api.resources_pb2 import Input, RunnerSelector
11
11
  from clarifai_grpc.grpc.api.status import status_code_pb2
12
12
  from google.protobuf.json_format import MessageToDict
13
13
  from google.protobuf.struct_pb2 import Struct, Value
@@ -19,15 +19,14 @@ from clarifai.client.dataset import Dataset
19
19
  from clarifai.client.deployment import Deployment
20
20
  from clarifai.client.input import Inputs
21
21
  from clarifai.client.lister import Lister
22
- from clarifai.client.model_client import ModelClient
23
22
  from clarifai.client.nodepool import Nodepool
24
- from clarifai.constants.model import (CHUNK_SIZE, MAX_CHUNK_SIZE, MAX_RANGE_SIZE, MIN_CHUNK_SIZE,
25
- MIN_RANGE_SIZE, MODEL_EXPORT_TIMEOUT, RANGE_SIZE,
26
- TRAINABLE_MODEL_TYPES)
23
+ from clarifai.constants.model import (CHUNK_SIZE, MAX_CHUNK_SIZE, MAX_MODEL_PREDICT_INPUTS,
24
+ MAX_RANGE_SIZE, MIN_CHUNK_SIZE, MIN_RANGE_SIZE,
25
+ MODEL_EXPORT_TIMEOUT, RANGE_SIZE, TRAINABLE_MODEL_TYPES)
27
26
  from clarifai.errors import UserError
28
27
  from clarifai.urls.helper import ClarifaiUrlHelper
29
28
  from clarifai.utils.logging import logger
30
- from clarifai.utils.misc import BackoffIterator
29
+ from clarifai.utils.misc import BackoffIterator, status_is_retryable
31
30
  from clarifai.utils.model_train import (find_and_replace_key, params_parser,
32
31
  response_to_model_params, response_to_param_info,
33
32
  response_to_templates)
@@ -48,9 +47,6 @@ class Model(Lister, BaseClient):
48
47
  pat: str = None,
49
48
  token: str = None,
50
49
  root_certificates_path: str = None,
51
- compute_cluster_id: str = None,
52
- nodepool_id: str = None,
53
- deployment_id: str = None,
54
50
  **kwargs):
55
51
  """Initializes a Model object.
56
52
 
@@ -77,12 +73,6 @@ class Model(Lister, BaseClient):
77
73
  self.logger = logger
78
74
  self.training_params = {}
79
75
  self.input_types = None
80
- self._model_client = None
81
- self._set_runner_selector(
82
- compute_cluster_id=compute_cluster_id,
83
- nodepool_id=nodepool_id,
84
- deployment_id=deployment_id,
85
- )
86
76
  BaseClient.__init__(
87
77
  self,
88
78
  user_id=self.user_id,
@@ -417,40 +407,49 @@ class Model(Lister, BaseClient):
417
407
  model_id=self.id,
418
408
  **dict(self.kwargs, model_version=model_version_info))
419
409
 
420
- @property
421
- def model_client(self):
422
- if self._model_client is None:
423
- request_template = service_pb2.PostModelOutputsRequest(
424
- user_app_id=self.user_app_id,
425
- model_id=self.id,
426
- version_id=self.model_version.id,
427
- model=self.model_info,
428
- runner_selector=self._runner_selector,
429
- )
430
- self._model_client = ModelClient(self.STUB, request_template=request_template)
431
- return self._model_client
432
-
433
- def predict(self, inputs: List[Input], inference_params: Dict = {}, output_config: Dict = {}):
410
+ def predict(self,
411
+ inputs: List[Input],
412
+ runner_selector: RunnerSelector = None,
413
+ inference_params: Dict = {},
414
+ output_config: Dict = {}):
434
415
  """Predicts the model based on the given inputs.
435
416
 
436
417
  Args:
437
418
  inputs (list[Input]): The inputs to predict, must be less than 128.
419
+ runner_selector (RunnerSelector): The runner selector to use for the model.
438
420
  """
439
-
440
- return self.model_client._predict_by_proto(
421
+ if not isinstance(inputs, list):
422
+ raise UserError('Invalid inputs, inputs must be a list of Input objects.')
423
+ if len(inputs) > MAX_MODEL_PREDICT_INPUTS:
424
+ raise UserError(f"Too many inputs. Max is {MAX_MODEL_PREDICT_INPUTS}."
425
+ ) # TODO Use Chunker for inputs len > 128
426
+
427
+ self._override_model_version(inference_params, output_config)
428
+ request = service_pb2.PostModelOutputsRequest(
429
+ user_app_id=self.user_app_id,
430
+ model_id=self.id,
431
+ version_id=self.model_version.id,
441
432
  inputs=inputs,
442
- inference_params=inference_params,
443
- output_config=output_config,
444
- )
433
+ runner_selector=runner_selector,
434
+ model=self.model_info)
445
435
 
446
- def predict2(self, inputs):
447
- """Predicts the model based on the given inputs.
436
+ start_time = time.time()
437
+ backoff_iterator = BackoffIterator(10)
438
+ while True:
439
+ response = self._grpc_request(self.STUB.PostModelOutputs, request)
448
440
 
449
- Args:
450
- inputs (list[Input]): The inputs to predict, must be less than 128.
451
- """
441
+ if status_is_retryable(response.status.code) and \
442
+ time.time() - start_time < 60 * 10: # 10 minutes
443
+ self.logger.info(f"{self.id} model is still deploying, please wait...")
444
+ time.sleep(next(backoff_iterator))
445
+ continue
446
+
447
+ if response.status.code != status_code_pb2.SUCCESS:
448
+ raise Exception(f"Model Predict failed with response {response.status!r}")
449
+ else:
450
+ break
452
451
 
453
- return self.model_client._predict(inputs=inputs,)
452
+ return response
454
453
 
455
454
  def _check_predict_input_type(self, input_type: str) -> None:
456
455
  """Checks if the input type is valid for the model.
@@ -498,41 +497,13 @@ class Model(Lister, BaseClient):
498
497
  raise Exception(response.status)
499
498
  self.input_types = response.model_type.input_fields
500
499
 
501
- def _set_runner_selector(self,
502
- compute_cluster_id: str = None,
503
- nodepool_id: str = None,
504
- deployment_id: str = None,
505
- user_id: str = None):
506
- runner_selector = None
507
- if deployment_id and (compute_cluster_id or nodepool_id):
508
- raise UserError(
509
- "You can only specify one of deployment_id or compute_cluster_id and nodepool_id.")
510
-
511
- if deployment_id:
512
- if not user_id and not os.environ.get('CLARIFAI_USER_ID'):
513
- raise UserError(
514
- "User ID is required for model prediction with deployment ID, please provide user_id in the method call."
515
- )
516
- if not user_id:
517
- user_id = os.environ.get('CLARIFAI_USER_ID')
518
- runner_selector = Deployment.get_runner_selector(
519
- user_id=user_id, deployment_id=deployment_id)
520
- elif compute_cluster_id and nodepool_id:
521
- if not user_id and not os.environ.get('CLARIFAI_USER_ID'):
522
- raise UserError(
523
- "User ID is required for model prediction with compute cluster ID and nodepool ID, please provide user_id in the method call."
524
- )
525
- if not user_id:
526
- user_id = os.environ.get('CLARIFAI_USER_ID')
527
- runner_selector = Nodepool.get_runner_selector(
528
- user_id=user_id, compute_cluster_id=compute_cluster_id, nodepool_id=nodepool_id)
529
-
530
- # set the runner selector
531
- self._runner_selector = runner_selector
532
-
533
500
  def predict_by_filepath(self,
534
501
  filepath: str,
535
502
  input_type: str = None,
503
+ compute_cluster_id: str = None,
504
+ nodepool_id: str = None,
505
+ deployment_id: str = None,
506
+ user_id: str = None,
536
507
  inference_params: Dict = {},
537
508
  output_config: Dict = {}):
538
509
  """Predicts the model based on the given filepath.
@@ -540,6 +511,9 @@ class Model(Lister, BaseClient):
540
511
  Args:
541
512
  filepath (str): The filepath to predict.
542
513
  input_type (str, optional): The type of input. Can be 'image', 'text', 'video' or 'audio.
514
+ compute_cluster_id (str): The compute cluster ID to use for the model.
515
+ nodepool_id (str): The nodepool ID to use for the model.
516
+ deployment_id (str): The deployment ID to use for the model.
543
517
  inference_params (dict): The inference params to override.
544
518
  output_config (dict): The output config to override.
545
519
  min_value (float): The minimum value of the prediction confidence to filter.
@@ -560,11 +534,16 @@ class Model(Lister, BaseClient):
560
534
  with open(filepath, "rb") as f:
561
535
  file_bytes = f.read()
562
536
 
563
- return self.predict_by_bytes(file_bytes, input_type, inference_params, output_config)
537
+ return self.predict_by_bytes(file_bytes, input_type, compute_cluster_id, nodepool_id,
538
+ deployment_id, user_id, inference_params, output_config)
564
539
 
565
540
  def predict_by_bytes(self,
566
541
  input_bytes: bytes,
567
542
  input_type: str = None,
543
+ compute_cluster_id: str = None,
544
+ nodepool_id: str = None,
545
+ deployment_id: str = None,
546
+ user_id: str = None,
568
547
  inference_params: Dict = {},
569
548
  output_config: Dict = {}):
570
549
  """Predicts the model based on the given bytes.
@@ -572,6 +551,9 @@ class Model(Lister, BaseClient):
572
551
  Args:
573
552
  input_bytes (bytes): File Bytes to predict on.
574
553
  input_type (str, optional): The type of input. Can be 'image', 'text', 'video' or 'audio.
554
+ compute_cluster_id (str): The compute cluster ID to use for the model.
555
+ nodepool_id (str): The nodepool ID to use for the model.
556
+ deployment_id (str): The deployment ID to use for the model.
575
557
  inference_params (dict): The inference params to override.
576
558
  output_config (dict): The output config to override.
577
559
  min_value (float): The minimum value of the prediction confidence to filter.
@@ -595,12 +577,43 @@ class Model(Lister, BaseClient):
595
577
  elif self.input_types[0] == "audio":
596
578
  input_proto = Inputs.get_input_from_bytes("", audio_bytes=input_bytes)
597
579
 
580
+ if deployment_id and (compute_cluster_id or nodepool_id):
581
+ raise UserError(
582
+ "You can only specify one of deployment_id or compute_cluster_id and nodepool_id.")
583
+
584
+ runner_selector = None
585
+ if deployment_id:
586
+ if not user_id and not os.environ.get('CLARIFAI_USER_ID'):
587
+ raise UserError(
588
+ "User ID is required for model prediction with deployment ID, please provide user_id in the method call."
589
+ )
590
+ if not user_id:
591
+ user_id = os.environ.get('CLARIFAI_USER_ID')
592
+ runner_selector = Deployment.get_runner_selector(
593
+ user_id=user_id, deployment_id=deployment_id)
594
+ elif compute_cluster_id and nodepool_id:
595
+ if not user_id and not os.environ.get('CLARIFAI_USER_ID'):
596
+ raise UserError(
597
+ "User ID is required for model prediction with compute cluster ID and nodepool ID, please provide user_id in the method call."
598
+ )
599
+ if not user_id:
600
+ user_id = os.environ.get('CLARIFAI_USER_ID')
601
+ runner_selector = Nodepool.get_runner_selector(
602
+ user_id=user_id, compute_cluster_id=compute_cluster_id, nodepool_id=nodepool_id)
603
+
598
604
  return self.predict(
599
- inputs=[input_proto], inference_params=inference_params, output_config=output_config)
605
+ inputs=[input_proto],
606
+ runner_selector=runner_selector,
607
+ inference_params=inference_params,
608
+ output_config=output_config)
600
609
 
601
610
  def predict_by_url(self,
602
611
  url: str,
603
612
  input_type: str = None,
613
+ compute_cluster_id: str = None,
614
+ nodepool_id: str = None,
615
+ deployment_id: str = None,
616
+ user_id: str = None,
604
617
  inference_params: Dict = {},
605
618
  output_config: Dict = {}):
606
619
  """Predicts the model based on the given URL.
@@ -608,6 +621,9 @@ class Model(Lister, BaseClient):
608
621
  Args:
609
622
  url (str): The URL to predict.
610
623
  input_type (str, optional): The type of input. Can be 'image', 'text', 'video' or 'audio'.
624
+ compute_cluster_id (str): The compute cluster ID to use for the model.
625
+ nodepool_id (str): The nodepool ID to use for the model.
626
+ deployment_id (str): The deployment ID to use for the model.
611
627
  inference_params (dict): The inference params to override.
612
628
  output_config (dict): The output config to override.
613
629
  min_value (float): The minimum value of the prediction confidence to filter.
@@ -632,31 +648,98 @@ class Model(Lister, BaseClient):
632
648
  elif self.input_types[0] == "audio":
633
649
  input_proto = Inputs.get_input_from_url("", audio_url=url)
634
650
 
651
+ if deployment_id and (compute_cluster_id or nodepool_id):
652
+ raise UserError(
653
+ "You can only specify one of deployment_id or compute_cluster_id and nodepool_id.")
654
+
655
+ runner_selector = None
656
+ if deployment_id:
657
+ if not user_id and not os.environ.get('CLARIFAI_USER_ID'):
658
+ raise UserError(
659
+ "User ID is required for model prediction with deployment ID, please provide user_id in the method call."
660
+ )
661
+ if not user_id:
662
+ user_id = os.environ.get('CLARIFAI_USER_ID')
663
+ runner_selector = Deployment.get_runner_selector(
664
+ user_id=user_id, deployment_id=deployment_id)
665
+ elif compute_cluster_id and nodepool_id:
666
+ if not user_id and not os.environ.get('CLARIFAI_USER_ID'):
667
+ raise UserError(
668
+ "User ID is required for model prediction with compute cluster ID and nodepool ID, please provide user_id in the method call."
669
+ )
670
+ if not user_id:
671
+ user_id = os.environ.get('CLARIFAI_USER_ID')
672
+ runner_selector = Nodepool.get_runner_selector(
673
+ user_id=user_id, compute_cluster_id=compute_cluster_id, nodepool_id=nodepool_id)
674
+
635
675
  return self.predict(
636
- inputs=[input_proto], inference_params=inference_params, output_config=output_config)
676
+ inputs=[input_proto],
677
+ runner_selector=runner_selector,
678
+ inference_params=inference_params,
679
+ output_config=output_config)
637
680
 
638
- def generate(
639
- self,
640
- inputs: List[Input],
641
- inference_params: Dict = {},
642
- output_config: Dict = {},
643
- ):
681
+ def generate(self,
682
+ inputs: List[Input],
683
+ runner_selector: RunnerSelector = None,
684
+ inference_params: Dict = {},
685
+ output_config: Dict = {}):
644
686
  """Generate the stream output on model based on the given inputs.
645
687
 
646
688
  Args:
647
689
  inputs (list[Input]): The inputs to generate, must be less than 128.
690
+ runner_selector (RunnerSelector): The runner selector to use for the model.
648
691
  inference_params (dict): The inference params to override.
649
- output_config (dict): The output config to override.
692
+
693
+ Example:
694
+ >>> from clarifai.client.model import Model
695
+ >>> model = Model("url") # Example URL: https://clarifai.com/clarifai/main/models/general-image-recognition
696
+ or
697
+ >>> model = Model(model_id='model_id', user_id='user_id', app_id='app_id')
698
+ >>> stream_response = model.generate(inputs=[input1, input2], runner_selector=runner_selector)
699
+ >>> list_stream_response = [response for response in stream_response]
650
700
  """
651
- return self.model_client._generate_by_proto(
701
+ if not isinstance(inputs, list):
702
+ raise UserError('Invalid inputs, inputs must be a list of Input objects.')
703
+ if len(inputs) > MAX_MODEL_PREDICT_INPUTS:
704
+ raise UserError(f"Too many inputs. Max is {MAX_MODEL_PREDICT_INPUTS}."
705
+ ) # TODO Use Chunker for inputs len > 128
706
+
707
+ self._override_model_version(inference_params, output_config)
708
+ request = service_pb2.PostModelOutputsRequest(
709
+ user_app_id=self.user_app_id,
710
+ model_id=self.id,
711
+ version_id=self.model_version.id,
652
712
  inputs=inputs,
653
- inference_params=inference_params,
654
- output_config=output_config,
655
- )
713
+ runner_selector=runner_selector,
714
+ model=self.model_info)
715
+
716
+ start_time = time.time()
717
+ backoff_iterator = BackoffIterator(10)
718
+ generation_started = False
719
+ while True:
720
+ if generation_started:
721
+ break
722
+ stream_response = self._grpc_request(self.STUB.GenerateModelOutputs, request)
723
+ for response in stream_response:
724
+ if status_is_retryable(response.status.code) and \
725
+ time.time() - start_time < 60 * 10:
726
+ self.logger.info(f"{self.id} model is still deploying, please wait...")
727
+ time.sleep(next(backoff_iterator))
728
+ break
729
+ if response.status.code != status_code_pb2.SUCCESS:
730
+ raise Exception(f"Model Predict failed with response {response.status!r}")
731
+ else:
732
+ if not generation_started:
733
+ generation_started = True
734
+ yield response
656
735
 
657
736
  def generate_by_filepath(self,
658
737
  filepath: str,
659
738
  input_type: str = None,
739
+ compute_cluster_id: str = None,
740
+ nodepool_id: str = None,
741
+ deployment_id: str = None,
742
+ user_id: str = None,
660
743
  inference_params: Dict = {},
661
744
  output_config: Dict = {}):
662
745
  """Generate the stream output on model based on the given filepath.
@@ -664,6 +747,9 @@ class Model(Lister, BaseClient):
664
747
  Args:
665
748
  filepath (str): The filepath to predict.
666
749
  input_type (str, optional): The type of input. Can be 'image', 'text', 'video' or 'audio.
750
+ compute_cluster_id (str): The compute cluster ID to use for the model.
751
+ nodepool_id (str): The nodepool ID to use for the model.
752
+ deployment_id (str): The deployment ID to use for the model.
667
753
  inference_params (dict): The inference params to override.
668
754
  output_config (dict): The output config to override.
669
755
  min_value (float): The minimum value of the prediction confidence to filter.
@@ -687,12 +773,20 @@ class Model(Lister, BaseClient):
687
773
  return self.generate_by_bytes(
688
774
  input_bytes=file_bytes,
689
775
  input_type=input_type,
776
+ compute_cluster_id=compute_cluster_id,
777
+ nodepool_id=nodepool_id,
778
+ deployment_id=deployment_id,
779
+ user_id=user_id,
690
780
  inference_params=inference_params,
691
781
  output_config=output_config)
692
782
 
693
783
  def generate_by_bytes(self,
694
784
  input_bytes: bytes,
695
785
  input_type: str = None,
786
+ compute_cluster_id: str = None,
787
+ nodepool_id: str = None,
788
+ deployment_id: str = None,
789
+ user_id: str = None,
696
790
  inference_params: Dict = {},
697
791
  output_config: Dict = {}):
698
792
  """Generate the stream output on model based on the given bytes.
@@ -700,6 +794,9 @@ class Model(Lister, BaseClient):
700
794
  Args:
701
795
  input_bytes (bytes): File Bytes to predict on.
702
796
  input_type (str, optional): The type of input. Can be 'image', 'text', 'video' or 'audio.
797
+ compute_cluster_id (str): The compute cluster ID to use for the model.
798
+ nodepool_id (str): The nodepool ID to use for the model.
799
+ deployment_id (str): The deployment ID to use for the model.
703
800
  inference_params (dict): The inference params to override.
704
801
  output_config (dict): The output config to override.
705
802
  min_value (float): The minimum value of the prediction confidence to filter.
@@ -725,12 +822,44 @@ class Model(Lister, BaseClient):
725
822
  elif self.input_types[0] == "audio":
726
823
  input_proto = Inputs.get_input_from_bytes("", audio_bytes=input_bytes)
727
824
 
825
+ if deployment_id and (compute_cluster_id or nodepool_id):
826
+ raise UserError(
827
+ "You can only specify one of deployment_id or compute_cluster_id and nodepool_id.")
828
+
829
+ runner_selector = None
830
+ if deployment_id:
831
+ if not user_id and not os.environ.get('CLARIFAI_USER_ID'):
832
+ raise UserError(
833
+ "User ID is required for model prediction with deployment ID, please provide user_id in the method call."
834
+ )
835
+ if not user_id:
836
+ user_id = os.environ.get('CLARIFAI_USER_ID')
837
+ runner_selector = Deployment.get_runner_selector(
838
+ user_id=user_id, deployment_id=deployment_id)
839
+
840
+ elif compute_cluster_id and nodepool_id:
841
+ if not user_id and not os.environ.get('CLARIFAI_USER_ID'):
842
+ raise UserError(
843
+ "User ID is required for model prediction with compute cluster ID and nodepool ID, please provide user_id in the method call."
844
+ )
845
+ if not user_id:
846
+ user_id = os.environ.get('CLARIFAI_USER_ID')
847
+ runner_selector = Nodepool.get_runner_selector(
848
+ user_id=user_id, compute_cluster_id=compute_cluster_id, nodepool_id=nodepool_id)
849
+
728
850
  return self.generate(
729
- inputs=[input_proto], inference_params=inference_params, output_config=output_config)
851
+ inputs=[input_proto],
852
+ runner_selector=runner_selector,
853
+ inference_params=inference_params,
854
+ output_config=output_config)
730
855
 
731
856
  def generate_by_url(self,
732
857
  url: str,
733
858
  input_type: str = None,
859
+ compute_cluster_id: str = None,
860
+ nodepool_id: str = None,
861
+ deployment_id: str = None,
862
+ user_id: str = None,
734
863
  inference_params: Dict = {},
735
864
  output_config: Dict = {}):
736
865
  """Generate the stream output on model based on the given URL.
@@ -738,6 +867,9 @@ class Model(Lister, BaseClient):
738
867
  Args:
739
868
  url (str): The URL to predict.
740
869
  input_type (str, optional): The type of input. Can be 'image', 'text', 'video' or 'audio.
870
+ compute_cluster_id (str): The compute cluster ID to use for the model.
871
+ nodepool_id (str): The nodepool ID to use for the model.
872
+ deployment_id (str): The deployment ID to use for the model.
741
873
  inference_params (dict): The inference params to override.
742
874
  output_config (dict): The output config to override.
743
875
  min_value (float): The minimum value of the prediction confidence to filter.
@@ -763,17 +895,56 @@ class Model(Lister, BaseClient):
763
895
  elif self.input_types[0] == "audio":
764
896
  input_proto = Inputs.get_input_from_url("", audio_url=url)
765
897
 
898
+ if deployment_id and (compute_cluster_id or nodepool_id):
899
+ raise UserError(
900
+ "You can only specify one of deployment_id or compute_cluster_id and nodepool_id.")
901
+
902
+ runner_selector = None
903
+ if deployment_id:
904
+ if not user_id and not os.environ.get('CLARIFAI_USER_ID'):
905
+ raise UserError(
906
+ "User ID is required for model prediction with deployment ID, please provide user_id in the method call."
907
+ )
908
+ if not user_id:
909
+ user_id = os.environ.get('CLARIFAI_USER_ID')
910
+ runner_selector = Deployment.get_runner_selector(
911
+ user_id=user_id, deployment_id=deployment_id)
912
+ elif compute_cluster_id and nodepool_id:
913
+ if not user_id and not os.environ.get('CLARIFAI_USER_ID'):
914
+ raise UserError(
915
+ "User ID is required for model prediction with compute cluster ID and nodepool ID, please provide user_id in the method call."
916
+ )
917
+ if not user_id:
918
+ user_id = os.environ.get('CLARIFAI_USER_ID')
919
+ runner_selector = Nodepool.get_runner_selector(
920
+ user_id=user_id, compute_cluster_id=compute_cluster_id, nodepool_id=nodepool_id)
921
+
766
922
  return self.generate(
767
- inputs=[input_proto], inference_params=inference_params, output_config=output_config)
923
+ inputs=[input_proto],
924
+ runner_selector=runner_selector,
925
+ inference_params=inference_params,
926
+ output_config=output_config)
927
+
928
+ def _req_iterator(self, input_iterator: Iterator[List[Input]], runner_selector: RunnerSelector):
929
+ for inputs in input_iterator:
930
+ yield service_pb2.PostModelOutputsRequest(
931
+ user_app_id=self.user_app_id,
932
+ model_id=self.id,
933
+ version_id=self.model_version.id,
934
+ inputs=inputs,
935
+ runner_selector=runner_selector,
936
+ model=self.model_info)
768
937
 
769
938
  def stream(self,
770
939
  inputs: Iterator[List[Input]],
940
+ runner_selector: RunnerSelector = None,
771
941
  inference_params: Dict = {},
772
942
  output_config: Dict = {}):
773
943
  """Generate the stream output on model based on the given stream of inputs.
774
944
 
775
945
  Args:
776
946
  inputs (Iterator[list[Input]]): stream of inputs to predict, must be less than 128.
947
+ runner_selector (RunnerSelector): The runner selector to use for the model.
777
948
 
778
949
  Example:
779
950
  >>> from clarifai.client.model import Model
@@ -783,15 +954,39 @@ class Model(Lister, BaseClient):
783
954
  >>> stream_response = model.stream(inputs=inputs, runner_selector=runner_selector)
784
955
  >>> list_stream_response = [response for response in stream_response]
785
956
  """
786
- return self.model_client._stream_by_proto(
787
- inputs=inputs,
788
- inference_params=inference_params,
789
- output_config=output_config,
790
- )
957
+ # if not isinstance(inputs, Iterator[List[Input]]):
958
+ # raise UserError('Invalid inputs, inputs must be a iterator of list of Input objects.')
959
+
960
+ self._override_model_version(inference_params, output_config)
961
+ request = self._req_iterator(inputs, runner_selector)
962
+
963
+ start_time = time.time()
964
+ backoff_iterator = BackoffIterator(10)
965
+ generation_started = False
966
+ while True:
967
+ if generation_started:
968
+ break
969
+ stream_response = self._grpc_request(self.STUB.StreamModelOutputs, request)
970
+ for response in stream_response:
971
+ if status_is_retryable(response.status.code) and \
972
+ time.time() - start_time < 60 * 10:
973
+ self.logger.info(f"{self.id} model is still deploying, please wait...")
974
+ time.sleep(next(backoff_iterator))
975
+ break
976
+ if response.status.code != status_code_pb2.SUCCESS:
977
+ raise Exception(f"Model Predict failed with response {response.status!r}")
978
+ else:
979
+ if not generation_started:
980
+ generation_started = True
981
+ yield response
791
982
 
792
983
  def stream_by_filepath(self,
793
984
  filepath: str,
794
985
  input_type: str = None,
986
+ compute_cluster_id: str = None,
987
+ nodepool_id: str = None,
988
+ deployment_id: str = None,
989
+ user_id: str = None,
795
990
  inference_params: Dict = {},
796
991
  output_config: Dict = {}):
797
992
  """Stream the model output based on the given filepath.
@@ -799,6 +994,9 @@ class Model(Lister, BaseClient):
799
994
  Args:
800
995
  filepath (str): The filepath to predict.
801
996
  input_type (str, optional): The type of input. Can be 'image', 'text', 'video' or 'audio.
997
+ compute_cluster_id (str): The compute cluster ID to use for the model.
998
+ nodepool_id (str): The nodepool ID to use for the model.
999
+ deployment_id (str): The deployment ID to use for the model.
802
1000
  inference_params (dict): The inference params to override.
803
1001
  output_config (dict): The output config to override.
804
1002
  min_value (float): The minimum value of the prediction confidence to filter.
@@ -820,12 +1018,20 @@ class Model(Lister, BaseClient):
820
1018
  return self.stream_by_bytes(
821
1019
  input_bytes_iterator=iter([file_bytes]),
822
1020
  input_type=input_type,
1021
+ compute_cluster_id=compute_cluster_id,
1022
+ nodepool_id=nodepool_id,
1023
+ deployment_id=deployment_id,
1024
+ user_id=user_id,
823
1025
  inference_params=inference_params,
824
1026
  output_config=output_config)
825
1027
 
826
1028
  def stream_by_bytes(self,
827
1029
  input_bytes_iterator: Iterator[bytes],
828
1030
  input_type: str = None,
1031
+ compute_cluster_id: str = None,
1032
+ nodepool_id: str = None,
1033
+ deployment_id: str = None,
1034
+ user_id: str = None,
829
1035
  inference_params: Dict = {},
830
1036
  output_config: Dict = {}):
831
1037
  """Stream the model output based on the given bytes.
@@ -833,6 +1039,9 @@ class Model(Lister, BaseClient):
833
1039
  Args:
834
1040
  input_bytes_iterator (Iterator[bytes]): Iterator of file bytes to predict on.
835
1041
  input_type (str, optional): The type of input. Can be 'image', 'text', 'video' or 'audio.
1042
+ compute_cluster_id (str): The compute cluster ID to use for the model.
1043
+ nodepool_id (str): The nodepool ID to use for the model.
1044
+ deployment_id (str): The deployment ID to use for the model.
836
1045
  inference_params (dict): The inference params to override.
837
1046
  output_config (dict): The output config to override.
838
1047
  min_value (float): The minimum value of the prediction confidence to filter.
@@ -860,12 +1069,43 @@ class Model(Lister, BaseClient):
860
1069
  elif self.input_types[0] == "audio":
861
1070
  yield [Inputs.get_input_from_bytes("", audio_bytes=input_bytes)]
862
1071
 
1072
+ if deployment_id and (compute_cluster_id or nodepool_id):
1073
+ raise UserError(
1074
+ "You can only specify one of deployment_id or compute_cluster_id and nodepool_id.")
1075
+
1076
+ runner_selector = None
1077
+ if deployment_id:
1078
+ if not user_id and not os.environ.get('CLARIFAI_USER_ID'):
1079
+ raise UserError(
1080
+ "User ID is required for model prediction with deployment ID, please provide user_id in the method call."
1081
+ )
1082
+ if not user_id:
1083
+ user_id = os.environ.get('CLARIFAI_USER_ID')
1084
+ runner_selector = Deployment.get_runner_selector(
1085
+ user_id=user_id, deployment_id=deployment_id)
1086
+ elif compute_cluster_id and nodepool_id:
1087
+ if not user_id and not os.environ.get('CLARIFAI_USER_ID'):
1088
+ raise UserError(
1089
+ "User ID is required for model prediction with compute cluster ID and nodepool ID, please provide user_id in the method call."
1090
+ )
1091
+ if not user_id:
1092
+ user_id = os.environ.get('CLARIFAI_USER_ID')
1093
+ runner_selector = Nodepool.get_runner_selector(
1094
+ user_id=user_id, compute_cluster_id=compute_cluster_id, nodepool_id=nodepool_id)
1095
+
863
1096
  return self.stream(
864
- inputs=input_generator(), inference_params=inference_params, output_config=output_config)
1097
+ inputs=input_generator(),
1098
+ runner_selector=runner_selector,
1099
+ inference_params=inference_params,
1100
+ output_config=output_config)
865
1101
 
866
1102
  def stream_by_url(self,
867
1103
  url_iterator: Iterator[str],
868
1104
  input_type: str = None,
1105
+ compute_cluster_id: str = None,
1106
+ nodepool_id: str = None,
1107
+ deployment_id: str = None,
1108
+ user_id: str = None,
869
1109
  inference_params: Dict = {},
870
1110
  output_config: Dict = {}):
871
1111
  """Stream the model output based on the given URL.
@@ -873,6 +1113,9 @@ class Model(Lister, BaseClient):
873
1113
  Args:
874
1114
  url_iterator (Iterator[str]): Iterator of URLs to predict.
875
1115
  input_type (str, optional): The type of input. Can be 'image', 'text', 'video' or 'audio.
1116
+ compute_cluster_id (str): The compute cluster ID to use for the model.
1117
+ nodepool_id (str): The nodepool ID to use for the model.
1118
+ deployment_id (str): The deployment ID to use for the model.
876
1119
  inference_params (dict): The inference params to override.
877
1120
  output_config (dict): The output config to override.
878
1121
  min_value (float): The minimum value of the prediction confidence to filter.
@@ -898,8 +1141,35 @@ class Model(Lister, BaseClient):
898
1141
  elif self.input_types[0] == "audio":
899
1142
  yield [Inputs.get_input_from_url("", audio_url=url)]
900
1143
 
1144
+ if deployment_id and (compute_cluster_id or nodepool_id):
1145
+ raise UserError(
1146
+ "You can only specify one of deployment_id or compute_cluster_id and nodepool_id.")
1147
+
1148
+ runner_selector = None
1149
+ if deployment_id:
1150
+ if not user_id and not os.environ.get('CLARIFAI_USER_ID'):
1151
+ raise UserError(
1152
+ "User ID is required for model prediction with deployment ID, please provide user_id in the method call."
1153
+ )
1154
+ if not user_id:
1155
+ user_id = os.environ.get('CLARIFAI_USER_ID')
1156
+ runner_selector = Deployment.get_runner_selector(
1157
+ user_id=user_id, deployment_id=deployment_id)
1158
+ elif compute_cluster_id and nodepool_id:
1159
+ if not user_id and not os.environ.get('CLARIFAI_USER_ID'):
1160
+ raise UserError(
1161
+ "User ID is required for model prediction with compute cluster ID and nodepool ID, please provide user_id in the method call."
1162
+ )
1163
+ if not user_id:
1164
+ user_id = os.environ.get('CLARIFAI_USER_ID')
1165
+ runner_selector = Nodepool.get_runner_selector(
1166
+ user_id=user_id, compute_cluster_id=compute_cluster_id, nodepool_id=nodepool_id)
1167
+
901
1168
  return self.stream(
902
- inputs=input_generator(), inference_params=inference_params, output_config=output_config)
1169
+ inputs=input_generator(),
1170
+ runner_selector=runner_selector,
1171
+ inference_params=inference_params,
1172
+ output_config=output_config)
903
1173
 
904
1174
  def _override_model_version(self, inference_params: Dict = {}, output_config: Dict = {}) -> None:
905
1175
  """Overrides the model version.