clarifai 11.4.6__tar.gz → 11.4.7__tar.gz

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 (134) hide show
  1. {clarifai-11.4.6/clarifai.egg-info → clarifai-11.4.7}/PKG-INFO +1 -1
  2. clarifai-11.4.7/clarifai/__init__.py +1 -0
  3. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/cli/base.py +3 -2
  4. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/cli/model.py +12 -12
  5. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/client/model.py +11 -21
  6. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/client/user.py +18 -0
  7. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/runners/utils/code_script.py +47 -6
  8. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/urls/helper.py +127 -17
  9. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/utils/config.py +38 -6
  10. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/utils/constants.py +2 -0
  11. {clarifai-11.4.6 → clarifai-11.4.7/clarifai.egg-info}/PKG-INFO +1 -1
  12. {clarifai-11.4.6 → clarifai-11.4.7}/tests/test_rag.py +0 -3
  13. clarifai-11.4.6/clarifai/__init__.py +0 -1
  14. {clarifai-11.4.6 → clarifai-11.4.7}/LICENSE +0 -0
  15. {clarifai-11.4.6 → clarifai-11.4.7}/MANIFEST.in +0 -0
  16. {clarifai-11.4.6 → clarifai-11.4.7}/README.md +0 -0
  17. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/cli/README.md +0 -0
  18. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/cli/__init__.py +0 -0
  19. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/cli/__main__.py +0 -0
  20. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/cli/compute_cluster.py +0 -0
  21. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/cli/deployment.py +0 -0
  22. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/cli/nodepool.py +0 -0
  23. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/cli.py +0 -0
  24. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/client/__init__.py +0 -0
  25. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/client/app.py +0 -0
  26. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/client/auth/__init__.py +0 -0
  27. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/client/auth/helper.py +0 -0
  28. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/client/auth/register.py +0 -0
  29. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/client/auth/stub.py +0 -0
  30. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/client/base.py +0 -0
  31. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/client/compute_cluster.py +0 -0
  32. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/client/dataset.py +0 -0
  33. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/client/deployment.py +0 -0
  34. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/client/input.py +0 -0
  35. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/client/lister.py +0 -0
  36. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/client/model_client.py +0 -0
  37. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/client/module.py +0 -0
  38. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/client/nodepool.py +0 -0
  39. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/client/runner.py +0 -0
  40. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/client/search.py +0 -0
  41. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/client/workflow.py +0 -0
  42. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/constants/base.py +0 -0
  43. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/constants/dataset.py +0 -0
  44. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/constants/input.py +0 -0
  45. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/constants/model.py +0 -0
  46. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/constants/rag.py +0 -0
  47. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/constants/search.py +0 -0
  48. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/constants/workflow.py +0 -0
  49. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/datasets/__init__.py +0 -0
  50. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/datasets/export/__init__.py +0 -0
  51. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/datasets/export/inputs_annotations.py +0 -0
  52. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/datasets/upload/__init__.py +0 -0
  53. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/datasets/upload/base.py +0 -0
  54. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/datasets/upload/features.py +0 -0
  55. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/datasets/upload/image.py +0 -0
  56. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/datasets/upload/loaders/README.md +0 -0
  57. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/datasets/upload/loaders/__init__.py +0 -0
  58. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/datasets/upload/loaders/coco_captions.py +0 -0
  59. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/datasets/upload/loaders/coco_detection.py +0 -0
  60. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/datasets/upload/loaders/imagenet_classification.py +0 -0
  61. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/datasets/upload/loaders/xview_detection.py +0 -0
  62. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/datasets/upload/multimodal.py +0 -0
  63. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/datasets/upload/text.py +0 -0
  64. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/datasets/upload/utils.py +0 -0
  65. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/errors.py +0 -0
  66. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/models/__init__.py +0 -0
  67. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/models/api.py +0 -0
  68. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/modules/README.md +0 -0
  69. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/modules/__init__.py +0 -0
  70. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/modules/css.py +0 -0
  71. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/modules/pages.py +0 -0
  72. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/modules/style.css +0 -0
  73. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/rag/__init__.py +0 -0
  74. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/rag/rag.py +0 -0
  75. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/rag/utils.py +0 -0
  76. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/runners/__init__.py +0 -0
  77. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/runners/dockerfile_template/Dockerfile.template +0 -0
  78. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/runners/models/__init__.py +0 -0
  79. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/runners/models/dummy_openai_model.py +0 -0
  80. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/runners/models/mcp_class.py +0 -0
  81. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/runners/models/model_builder.py +0 -0
  82. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/runners/models/model_class.py +0 -0
  83. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/runners/models/model_run_locally.py +0 -0
  84. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/runners/models/model_runner.py +0 -0
  85. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/runners/models/model_servicer.py +0 -0
  86. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/runners/models/openai_class.py +0 -0
  87. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/runners/models/visual_classifier_class.py +0 -0
  88. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/runners/models/visual_detector_class.py +0 -0
  89. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/runners/server.py +0 -0
  90. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/runners/utils/__init__.py +0 -0
  91. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/runners/utils/const.py +0 -0
  92. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/runners/utils/data_types/__init__.py +0 -0
  93. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/runners/utils/data_types/data_types.py +0 -0
  94. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/runners/utils/data_utils.py +0 -0
  95. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/runners/utils/loader.py +0 -0
  96. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/runners/utils/method_signatures.py +0 -0
  97. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/runners/utils/openai_convertor.py +0 -0
  98. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/runners/utils/serializers.py +0 -0
  99. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/runners/utils/url_fetcher.py +0 -0
  100. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/schema/search.py +0 -0
  101. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/utils/__init__.py +0 -0
  102. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/utils/cli.py +0 -0
  103. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/utils/evaluation/__init__.py +0 -0
  104. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/utils/evaluation/helpers.py +0 -0
  105. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/utils/evaluation/main.py +0 -0
  106. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/utils/evaluation/testset_annotation_parser.py +0 -0
  107. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/utils/logging.py +0 -0
  108. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/utils/misc.py +0 -0
  109. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/utils/model_train.py +0 -0
  110. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/utils/protobuf.py +0 -0
  111. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/versions.py +0 -0
  112. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/workflows/__init__.py +0 -0
  113. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/workflows/export.py +0 -0
  114. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/workflows/utils.py +0 -0
  115. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai/workflows/validate.py +0 -0
  116. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai.egg-info/SOURCES.txt +0 -0
  117. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai.egg-info/dependency_links.txt +0 -0
  118. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai.egg-info/entry_points.txt +0 -0
  119. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai.egg-info/requires.txt +0 -0
  120. {clarifai-11.4.6 → clarifai-11.4.7}/clarifai.egg-info/top_level.txt +0 -0
  121. {clarifai-11.4.6 → clarifai-11.4.7}/pyproject.toml +0 -0
  122. {clarifai-11.4.6 → clarifai-11.4.7}/requirements.txt +0 -0
  123. {clarifai-11.4.6 → clarifai-11.4.7}/setup.cfg +0 -0
  124. {clarifai-11.4.6 → clarifai-11.4.7}/setup.py +0 -0
  125. {clarifai-11.4.6 → clarifai-11.4.7}/tests/test_app.py +0 -0
  126. {clarifai-11.4.6 → clarifai-11.4.7}/tests/test_auth.py +0 -0
  127. {clarifai-11.4.6 → clarifai-11.4.7}/tests/test_data_upload.py +0 -0
  128. {clarifai-11.4.6 → clarifai-11.4.7}/tests/test_eval.py +0 -0
  129. {clarifai-11.4.6 → clarifai-11.4.7}/tests/test_misc.py +0 -0
  130. {clarifai-11.4.6 → clarifai-11.4.7}/tests/test_model_predict.py +0 -0
  131. {clarifai-11.4.6 → clarifai-11.4.7}/tests/test_model_train.py +0 -0
  132. {clarifai-11.4.6 → clarifai-11.4.7}/tests/test_modules.py +0 -0
  133. {clarifai-11.4.6 → clarifai-11.4.7}/tests/test_search.py +0 -0
  134. {clarifai-11.4.6 → clarifai-11.4.7}/tests/test_stub.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: clarifai
3
- Version: 11.4.6
3
+ Version: 11.4.7
4
4
  Home-page: https://github.com/Clarifai/clarifai-python
5
5
  Author: Clarifai
6
6
  Author-email: support@clarifai.com
@@ -0,0 +1 @@
1
+ __version__ = "11.4.7"
@@ -8,7 +8,7 @@ import yaml
8
8
 
9
9
  from clarifai.utils.cli import AliasedGroup, TableFormatter, load_command_modules
10
10
  from clarifai.utils.config import Config, Context
11
- from clarifai.utils.constants import DEFAULT_CONFIG
11
+ from clarifai.utils.constants import DEFAULT_BASE, DEFAULT_CONFIG, DEFAULT_UI
12
12
  from clarifai.utils.logging import logger
13
13
 
14
14
 
@@ -31,7 +31,8 @@ def cli(ctx, config):
31
31
  'default',
32
32
  CLARIFAI_PAT=os.environ.get('CLARIFAI_PAT', ''),
33
33
  CLARIFAI_USER_ID=os.environ.get('CLARIFAI_USER_ID', ''),
34
- CLARIFAI_API_BASE=os.environ.get('CLARIFAI_API_BASE', 'api.clarifai.com'),
34
+ CLARIFAI_API_BASE=DEFAULT_BASE,
35
+ CLARIFAI_UI=DEFAULT_UI,
35
36
  )
36
37
  },
37
38
  )
@@ -505,7 +505,7 @@ def local_dev(ctx, model_path):
505
505
  logger.info(f"Current deployment_id: {deployment_id}")
506
506
 
507
507
  logger.info(
508
- f"Full url for the model: /users/{user_id}/apps/{app_id}/models/{model.id}/versions/{version.id}"
508
+ f"Full url for the model: {ctx.obj.current.ui}/users/{user_id}/apps/{app_id}/models/{model.id}/versions/{version.id}"
509
509
  )
510
510
 
511
511
  # Now that we have all the context in ctx.obj, we need to update the config.yaml in
@@ -542,7 +542,6 @@ def local_dev(ctx, model_path):
542
542
  app_id=app_id,
543
543
  model_id=model_id,
544
544
  deployment_id=deployment_id,
545
- use_ctx=True,
546
545
  base_url=ctx.obj.current.api_base,
547
546
  )
548
547
 
@@ -683,7 +682,14 @@ def predict(
683
682
  "Either --compute_cluster_id & --nodepool_id or --deployment_id must be provided."
684
683
  )
685
684
  if model_url:
686
- model = Model(url=model_url, pat=ctx.obj['pat'], base_url=ctx.obj['base_url'])
685
+ model = Model(
686
+ url=model_url,
687
+ pat=ctx.obj['pat'],
688
+ base_url=ctx.obj['base_url'],
689
+ compute_cluster_id=compute_cluster_id,
690
+ nodepool_id=nodepool_id,
691
+ deployment_id=deployment_id,
692
+ )
687
693
  else:
688
694
  model = Model(
689
695
  model_id=model_id,
@@ -691,6 +697,9 @@ def predict(
691
697
  app_id=app_id,
692
698
  pat=ctx.obj['pat'],
693
699
  base_url=ctx.obj['base_url'],
700
+ compute_cluster_id=compute_cluster_id,
701
+ nodepool_id=nodepool_id,
702
+ deployment_id=deployment_id,
694
703
  )
695
704
 
696
705
  if inference_params:
@@ -702,9 +711,6 @@ def predict(
702
711
  model_prediction = model.predict_by_filepath(
703
712
  filepath=file_path,
704
713
  input_type=input_type,
705
- compute_cluster_id=compute_cluster_id,
706
- nodepool_id=nodepool_id,
707
- deployment_id=deployment_id,
708
714
  inference_params=inference_params,
709
715
  output_config=output_config,
710
716
  )
@@ -712,9 +718,6 @@ def predict(
712
718
  model_prediction = model.predict_by_url(
713
719
  url=url,
714
720
  input_type=input_type,
715
- compute_cluster_id=compute_cluster_id,
716
- nodepool_id=nodepool_id,
717
- deployment_id=deployment_id,
718
721
  inference_params=inference_params,
719
722
  output_config=output_config,
720
723
  )
@@ -723,9 +726,6 @@ def predict(
723
726
  model_prediction = model.predict_by_bytes(
724
727
  input_bytes=bytes,
725
728
  input_type=input_type,
726
- compute_cluster_id=compute_cluster_id,
727
- nodepool_id=nodepool_id,
728
- deployment_id=deployment_id,
729
729
  inference_params=inference_params,
730
730
  output_config=output_config,
731
731
  ) ## TO DO: Add support for input_id
@@ -108,7 +108,6 @@ class Model(Lister, BaseClient):
108
108
  compute_cluster_id=compute_cluster_id,
109
109
  nodepool_id=nodepool_id,
110
110
  deployment_id=deployment_id,
111
- user_id=self.user_id, # FIXME the deployment's user_id can be different than the model's.
112
111
  )
113
112
  BaseClient.__init__(
114
113
  self,
@@ -123,14 +122,12 @@ class Model(Lister, BaseClient):
123
122
 
124
123
  @classmethod
125
124
  def from_current_context(cls, **kwargs) -> 'Model':
126
- from clarifai.utils.config import Config
125
+ from clarifai.urls.helper import ClarifaiUrlHelper
127
126
 
128
- current = Config.from_yaml().current
129
-
130
- # set the current context to env vars.
131
- current.set_to_env()
132
-
133
- url = f"https://clarifai.com/{current.user_id}/{current.app_id}/models/{current.model_id}"
127
+ # passing None to ClarifaiUrlHelper uses the current context to set it up.
128
+ url_helper = ClarifaiUrlHelper()
129
+ current = url_helper.current_ctx
130
+ url = url_helper.clarifai_url(resource_type="models", resource_id=current.model_id)
134
131
 
135
132
  # construct the Model object.
136
133
  kwargs = {}
@@ -601,8 +598,13 @@ class Model(Lister, BaseClient):
601
598
  compute_cluster_id: str = None,
602
599
  nodepool_id: str = None,
603
600
  deployment_id: str = None,
604
- user_id: str = None,
605
601
  ):
602
+ # Get UserID
603
+ if any([deployment_id, nodepool_id, compute_cluster_id]):
604
+ from clarifai.client.user import User
605
+
606
+ user_id = User().get_user_info(user_id='me').user.id
607
+
606
608
  runner_selector = None
607
609
  if deployment_id and (compute_cluster_id or nodepool_id):
608
610
  raise UserError(
@@ -610,22 +612,10 @@ class Model(Lister, BaseClient):
610
612
  )
611
613
 
612
614
  if deployment_id:
613
- if not user_id and not os.environ.get('CLARIFAI_USER_ID'):
614
- raise UserError(
615
- "User ID is required for model prediction with deployment ID, please provide user_id in the method call."
616
- )
617
- if not user_id:
618
- user_id = os.environ.get('CLARIFAI_USER_ID')
619
615
  runner_selector = Deployment.get_runner_selector(
620
616
  user_id=user_id, deployment_id=deployment_id
621
617
  )
622
618
  elif compute_cluster_id and nodepool_id:
623
- if not user_id and not os.environ.get('CLARIFAI_USER_ID'):
624
- raise UserError(
625
- "User ID is required for model prediction with compute cluster ID and nodepool ID, please provide user_id in the method call."
626
- )
627
- if not user_id:
628
- user_id = os.environ.get('CLARIFAI_USER_ID')
629
619
  runner_selector = Nodepool.get_runner_selector(
630
620
  user_id=user_id, compute_cluster_id=compute_cluster_id, nodepool_id=nodepool_id
631
621
  )
@@ -427,6 +427,24 @@ class User(Lister, BaseClient):
427
427
  raise Exception(response.status)
428
428
  self.logger.info("\nCompute Cluster Deleted\n%s", response.status)
429
429
 
430
+ def get_user_info(self, user_id: str = None) -> resources_pb2.User:
431
+ """Returns the user information for the specified user ID.
432
+
433
+ Args:
434
+ user_id (str): The user ID for the user to interact with.
435
+
436
+ Returns:
437
+ User: A User object for the specified user ID.
438
+ """
439
+ request = service_pb2.GetUserRequest(
440
+ user_app_id=resources_pb2.UserAppIDSet(user_id=user_id if user_id else self.id)
441
+ )
442
+ response = self._grpc_request(self.STUB.GetUser, request)
443
+ if response.status.code != status_code_pb2.SUCCESS:
444
+ raise Exception(response.status)
445
+
446
+ return response
447
+
430
448
  def __getattr__(self, name):
431
449
  return getattr(self.user_info, name)
432
450
 
@@ -5,6 +5,20 @@ from clarifai_grpc.grpc.api import resources_pb2
5
5
 
6
6
  from clarifai.runners.utils import data_utils
7
7
  from clarifai.urls.helper import ClarifaiUrlHelper
8
+ from clarifai.utils.constants import MCP_TRANSPORT_NAME, OPENAI_TRANSPORT_NAME
9
+
10
+
11
+ def has_signature_method(
12
+ name: str, method_signatures: List[resources_pb2.MethodSignature]
13
+ ) -> bool:
14
+ """
15
+ Check if a method signature with the given name exists in the list of method signatures.
16
+
17
+ :param name: The name of the method to check.
18
+ :param method_signatures: List of MethodSignature objects to search in.
19
+ :return: True if a method with the given name exists, False otherwise.
20
+ """
21
+ return any(method_signature.name == name for method_signature in method_signatures)
8
22
 
9
23
 
10
24
  def generate_client_script(
@@ -18,12 +32,11 @@ def generate_client_script(
18
32
  ) -> str:
19
33
  url_helper = ClarifaiUrlHelper()
20
34
 
21
- # Provide an mcp client config
22
- if len(method_signatures) == 1 and method_signatures[0].name == "mcp_transport":
23
- api_url = url_helper.api_url(
35
+ # Provide an mcp client config if there is a method named "mcp_transport"
36
+ if has_signature_method(MCP_TRANSPORT_NAME, method_signatures):
37
+ mcp_url = url_helper.mcp_api_url(
24
38
  user_id,
25
39
  app_id,
26
- "models",
27
40
  model_id,
28
41
  )
29
42
 
@@ -33,20 +46,48 @@ import os
33
46
  from fastmcp import Client
34
47
  from fastmcp.client.transports import StreamableHttpTransport
35
48
 
36
- transport = StreamableHttpTransport(url="%s/mcp",
49
+ transport = StreamableHttpTransport(url="%s",
37
50
  headers={"Authorization": "Bearer " + os.environ["CLARIFAI_PAT"]})
38
51
 
39
52
  async def main():
40
53
  async with Client(transport) as client:
41
54
  tools = await client.list_tools()
42
55
  print(f"Available tools: {tools}")
56
+ # TODO: update the dictionary of arguments passed to call_tool to make sense for your MCP.
43
57
  result = await client.call_tool(tools[0].name, {"a": 5, "b": 3})
44
58
  print(f"Result: {result[0].text}")
45
59
 
46
60
  if __name__ == "__main__":
47
61
  asyncio.run(main())
48
62
  """
49
- return _CLIENT_TEMPLATE % api_url
63
+ return _CLIENT_TEMPLATE % mcp_url
64
+
65
+ if has_signature_method(OPENAI_TRANSPORT_NAME, method_signatures):
66
+ openai_api_base = url_helper.openai_api_url()
67
+ model_ui_url = url_helper.clarifai_url(user_id, app_id, "models", model_id)
68
+ _CLIENT_TEMPLATE = """
69
+ import os
70
+ from openai import OpenAI
71
+
72
+ client = OpenAI(
73
+ base_url="%s",
74
+ api_key=os.environ['CLARIFAI_PAT'],
75
+ )
76
+ response = client.chat.completions.create(
77
+ model="%s",
78
+ messages=[
79
+ {"role": "developer", "content": "Talk like a pirate."},
80
+ {
81
+ "role": "user",
82
+ "content": "How do I check if a Python object is an instance of a class?",
83
+ },
84
+ ],
85
+ temperature=0.7,
86
+ stream=False, # stream=True also works, just iterator over the response
87
+ )
88
+ print(response)
89
+ """
90
+ return _CLIENT_TEMPLATE % (openai_api_base, model_ui_url)
50
91
 
51
92
  _CLIENT_TEMPLATE = """\
52
93
  import os
@@ -1,15 +1,8 @@
1
- import os
2
1
  from collections import namedtuple
3
2
  from urllib.parse import urlparse
4
3
 
5
- from clarifai.utils.constants import DEFAULT_BASE, DEFAULT_UI
6
-
7
4
  # To help with using ClarifaiUrlHelper with defaults as ClarifaiUrlHelper()
8
5
  auth_obj = namedtuple("auth", ["ui", "base"])
9
- default_auth = auth_obj(
10
- ui=os.environ.get("CLARIFAI_UI", DEFAULT_UI),
11
- base=os.environ.get("CLARIFAI_API_BASE", DEFAULT_BASE),
12
- )
13
6
 
14
7
 
15
8
  class ClarifaiUrlHelper(object):
@@ -17,15 +10,19 @@ class ClarifaiUrlHelper(object):
17
10
 
18
11
  def __init__(
19
12
  self,
20
- auth=default_auth,
13
+ auth=None,
21
14
  module_manager_imv_id: str = "module_manager_install",
22
15
  ):
23
16
  """
24
17
  Args:
25
- auth: a ClarifaiAuthHelper object.
18
+ auth: a ClarifaiAuthHelper object. Pass None to use the values from the current context.
19
+ module_manager_imv_id: the ID of the module manager installed module version.
26
20
  """
27
21
  self._auth = auth
28
22
  self._module_manager_imv_id = module_manager_imv_id
23
+ self._current_context = None
24
+ if self._auth is None:
25
+ self._auth = auth_obj(self.current_ctx.ui, self.current_ctx.api_base)
29
26
 
30
27
  @property
31
28
  def ui(self):
@@ -35,8 +32,31 @@ class ClarifaiUrlHelper(object):
35
32
  def base(self):
36
33
  return self._auth.base
37
34
 
38
- def module_ui_url(self, user_id, app_id, module_id, module_version_id):
35
+ @property
36
+ def current_ctx(self):
37
+ if self._current_context is None:
38
+ from clarifai.utils.config import Config
39
+
40
+ self._current_context = Config.from_yaml().current
41
+ return self._current_context
42
+
43
+ def module_ui_url(
44
+ self,
45
+ user_id: str = None,
46
+ app_id: str = None,
47
+ module_id: str = None,
48
+ module_version_id: str = None,
49
+ ):
39
50
  """This is the path to the module in community."""
51
+ if user_id is None:
52
+ user_id = self.current_ctx.user_id
53
+ if app_id is None:
54
+ app_id = self.current_ctx.app_id
55
+ if module_id is None:
56
+ module_id = self.current_ctx.module_id
57
+ if module_version_id is None:
58
+ module_version_id = self.current_ctx.module_version_id
59
+
40
60
  return "%s/%s/%s/modules/%s/versions/%s" % (
41
61
  self.ui,
42
62
  user_id,
@@ -45,9 +65,17 @@ class ClarifaiUrlHelper(object):
45
65
  module_version_id,
46
66
  )
47
67
 
48
- def module_install_ui_url(self, dest_user_id, dest_app_id, module_url):
68
+ def module_install_ui_url(
69
+ self, dest_user_id: str = None, dest_app_id: str = None, module_url: str = None
70
+ ):
49
71
  """This is a url that allows for installation of the module from the community at 'module_url'
50
72
  into the destination app_id of the destination user_id."""
73
+ if dest_user_id is None:
74
+ dest_user_id = self.current_ctx.user_id
75
+ if dest_app_id is None:
76
+ dest_app_id = self.current_ctx.app_id
77
+ if module_url is None:
78
+ raise ValueError("module_url must be provided to install a module.")
51
79
  return "%s/%s/%s/installed_module_versions/%s/install?install=%s" % (
52
80
  self.ui,
53
81
  dest_user_id,
@@ -56,7 +84,14 @@ class ClarifaiUrlHelper(object):
56
84
  module_url,
57
85
  )
58
86
 
59
- def imv_ui_url(self, dest_user_id, dest_app_id, imv_id):
87
+ def imv_ui_url(self, dest_user_id: str = None, dest_app_id: str = None, imv_id: str = None):
88
+ """This is the path to the resource in the UI."""
89
+ if dest_user_id is None:
90
+ dest_user_id = self.current_ctx.user_id
91
+ if dest_app_id is None:
92
+ dest_app_id = self.current_ctx.app_id
93
+ if imv_id is None:
94
+ raise ValueError("imv_id must be provided to get the IMV API URL.")
60
95
  return "%s/%s/%s/installed_module_versions/%s" % (
61
96
  self.ui,
62
97
  dest_user_id,
@@ -64,7 +99,63 @@ class ClarifaiUrlHelper(object):
64
99
  imv_id,
65
100
  )
66
101
 
67
- def api_url(self, user_id, app_id, resource_type, resource_id, version_id: str = None):
102
+ def mcp_api_url(
103
+ self, user_id: str = None, app_id: str = None, model_id: str = None, version_id: str = None
104
+ ):
105
+ """We have a special endpoint for MCP hosted models.
106
+
107
+ Example:
108
+ https://api.clarifai.com/v2/ext/mcp/v1/users/{user_id}/apps/{app_id}/models/{model_id}/versions/{version_id}
109
+
110
+ Args:
111
+ user_id: the author of the resource.
112
+ app_id: the author's app the resource was created in.
113
+ model_id: the resource ID
114
+ version_id: the version of the resource.
115
+ """
116
+ if user_id is None:
117
+ user_id = self.current_ctx.user_id
118
+ if app_id is None:
119
+ app_id = self.current_ctx.app_id
120
+ if model_id is None:
121
+ model_id = self.current_ctx.model_id
122
+ if version_id is None:
123
+ return "%s/v2/ext/mcp/v1/users/%s/apps/%s/models/%s" % (
124
+ self.base,
125
+ user_id,
126
+ app_id,
127
+ model_id,
128
+ )
129
+ return "%s/v2/ext/mcp/v1/users/%s/apps/%s/models/%s/versions/%s" % (
130
+ self.base,
131
+ user_id,
132
+ app_id,
133
+ model_id,
134
+ version_id,
135
+ )
136
+
137
+ def openai_api_url(self):
138
+ """We have a special endpoint for openAI compatible models.
139
+
140
+ This doesn't include the /chat/completions suffix which the openAI client automatically
141
+ adds.
142
+
143
+ It also doesn't incldue the model which you an set as the model arg in an openAI client call
144
+ using the clarifai_url() method below.
145
+
146
+ Example:
147
+ https://api.clarifai.com/v2/ext/openai/v1
148
+ """
149
+ return "%s/v2/ext/openai/v1" % self.base
150
+
151
+ def api_url(
152
+ self,
153
+ user_id: str = None,
154
+ app_id: str = None,
155
+ resource_type: str = None,
156
+ resource_id: str = None,
157
+ version_id: str = None,
158
+ ):
68
159
  """This is the path to the resource in the API.
69
160
 
70
161
  Example:
@@ -81,6 +172,12 @@ class ClarifaiUrlHelper(object):
81
172
  resource_type: the type of resource. One of "modules", "models", "concepts", "inputs", "workflows", "tasks"
82
173
  resource_id: the resource ID
83
174
  """
175
+ if user_id is None:
176
+ user_id = self.current_ctx.user_id
177
+ if app_id is None:
178
+ app_id = self.current_ctx.app_id
179
+ if resource_id is None:
180
+ raise ValueError("resource_id must be provided to get the API URL.")
84
181
  self._validate_resource_type(resource_type)
85
182
  if version_id is None:
86
183
  return "%s/v2/users/%s/apps/%s/%s/%s" % (
@@ -117,7 +214,14 @@ class ClarifaiUrlHelper(object):
117
214
  % resource_type
118
215
  )
119
216
 
120
- def clarifai_url(self, user_id, app_id, resource_type, resource_id, version_id: str = None):
217
+ def clarifai_url(
218
+ self,
219
+ user_id: str = None,
220
+ app_id: str = None,
221
+ resource_type: str = None,
222
+ resource_id: str = None,
223
+ version_id: str = None,
224
+ ):
121
225
  """This is the path to the resource in community UI.
122
226
 
123
227
  Example:
@@ -135,6 +239,12 @@ class ClarifaiUrlHelper(object):
135
239
  resource_id: the resource ID
136
240
  version_id: the version of the resource.
137
241
  """
242
+ if user_id is None:
243
+ user_id = self.current_ctx.user_id
244
+ if app_id is None:
245
+ app_id = self.current_ctx.app_id
246
+ if resource_id is None:
247
+ raise ValueError("resource_id must be provided to get the API URL.")
138
248
  self._validate_resource_type(resource_type)
139
249
  if version_id is None:
140
250
  return "%s/%s/%s/%s/%s" % (self.ui, user_id, app_id, resource_type, resource_id)
@@ -148,7 +258,7 @@ class ClarifaiUrlHelper(object):
148
258
  )
149
259
 
150
260
  @classmethod
151
- def split_clarifai_app_url(cls, url):
261
+ def split_clarifai_app_url(cls, url: str):
152
262
  """
153
263
  clarifai.com uses fully qualified urls to resources.
154
264
  They are in the format of:
@@ -166,7 +276,7 @@ class ClarifaiUrlHelper(object):
166
276
  return tuple(parts[1:])
167
277
 
168
278
  @classmethod
169
- def split_clarifai_url(cls, url):
279
+ def split_clarifai_url(cls, url: str):
170
280
  """
171
281
  clarifai.com uses fully qualified urls to resources.
172
282
  They are in the format of:
@@ -191,7 +301,7 @@ class ClarifaiUrlHelper(object):
191
301
  return user_id, app_id, resource_type, resource_id, resource_version_id
192
302
 
193
303
  @classmethod
194
- def split_module_ui_url(cls, install):
304
+ def split_module_ui_url(cls, install: str):
195
305
  """Takes in a path like https://clarifai.com/zeiler/app/modules/module1/versions/2 to split it apart into it's IDs.
196
306
 
197
307
  Returns:
@@ -4,7 +4,8 @@ from dataclasses import dataclass, field
4
4
 
5
5
  import yaml
6
6
 
7
- from clarifai.utils.constants import DEFAULT_CONFIG
7
+ from clarifai.utils.constants import DEFAULT_BASE, DEFAULT_CONFIG, DEFAULT_UI
8
+ from clarifai.utils.logging import logger
8
9
 
9
10
 
10
11
  class Context(OrderedDict):
@@ -23,6 +24,12 @@ class Context(OrderedDict):
23
24
  self['env'] = kwargs
24
25
 
25
26
  def __getattr__(self, key):
27
+ """Get the key from the config. You can pass a lowercase key like "pat" and it will check if
28
+ the environment variable CLARIFAI_PAT set and use that first. If no env var, then it checks
29
+ if that env var name is in the config and use that. If not then checks if
30
+ "pat" is in the config, if not then it falls back to CLARIFAI_PAT in the environment
31
+ variables, else raises an AttributeError.
32
+ """
26
33
  try:
27
34
  if key == 'name':
28
35
  return self[key]
@@ -32,7 +39,9 @@ class Context(OrderedDict):
32
39
  # Allow accessing CLARIFAI_PAT type env var names from config as .pat
33
40
  envvar_name = 'CLARIFAI_' + key.upper()
34
41
  env = self['env']
35
- if envvar_name in env:
42
+ if envvar_name in os.environ: # environment variable take precedence.
43
+ value = os.environ[envvar_name]
44
+ elif envvar_name in env:
36
45
  value = env[envvar_name]
37
46
  if value == "ENVVAR":
38
47
  if envvar_name not in os.environ:
@@ -40,8 +49,17 @@ class Context(OrderedDict):
40
49
  f"Environment variable '{envvar_name}' not set. Attempting to load it for config '{self['name']}'. Please set it in your terminal."
41
50
  )
42
51
  return os.environ[envvar_name]
43
- else:
52
+ elif key in env: # check if key is in the config
44
53
  value = env[key]
54
+ # below are some default fallback values for UI and API base.
55
+ elif envvar_name == 'CLARIFAI_UI':
56
+ value = DEFAULT_UI
57
+ elif envvar_name == 'CLARIFAI_API_BASE':
58
+ value = DEFAULT_BASE
59
+ else:
60
+ raise AttributeError(
61
+ f"'{type(self).__name__}' object has no attribute '{key}' or '{envvar_name}' and '{envvar_name}' is also not in os.environ:"
62
+ )
45
63
 
46
64
  if isinstance(value, dict):
47
65
  return Context(value)
@@ -136,8 +154,17 @@ class Config:
136
154
 
137
155
  @classmethod
138
156
  def from_yaml(cls, filename: str = DEFAULT_CONFIG):
139
- with open(filename, 'r') as f:
140
- cfg = yaml.safe_load(f)
157
+ """Loads the configuration from a YAML file.
158
+ If the file does not exist, it initializes with empty config.
159
+ """
160
+ cfg = {"current_context": "_empty_", "contexts": {"_empty_": {}}}
161
+ if os.path.exists(filename):
162
+ with open(filename, 'r') as f:
163
+ cfg = yaml.safe_load(f)
164
+ else:
165
+ logger.warning(
166
+ f"Config file {filename} not found, using default config. Run 'clarifai config' on the command line to create a config file."
167
+ )
141
168
  return cls(**cfg, filename=filename)
142
169
 
143
170
  def to_dict(self):
@@ -160,5 +187,10 @@ class Config:
160
187
 
161
188
  @property
162
189
  def current(self) -> Context:
163
- """get the current Context"""
190
+ """Get the current Context or an empty one if your config is not setup."""
191
+ if not self.current_context:
192
+ logger.warning(
193
+ "No current context set, returning empty context. Run 'clarifai config' on the command line to create a config file."
194
+ )
195
+ return Context("_empty_")
164
196
  return self.contexts[self.current_context]
@@ -3,6 +3,8 @@ import os
3
3
  DEFAULT_UI = os.environ.get("CLARIFAI_UI", "https://clarifai.com")
4
4
  DEFAULT_BASE = os.environ.get("CLARIFAI_API_BASE", "https://api.clarifai.com")
5
5
 
6
+ MCP_TRANSPORT_NAME = "mcp_transport"
7
+ OPENAI_TRANSPORT_NAME = "openai_transport"
6
8
 
7
9
  CLARIFAI_PAT_ENV_VAR = "CLARIFAI_PAT"
8
10
  CLARIFAI_SESSION_TOKEN_ENV_VAR = "CLARIFAI_SESSION_TOKEN"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: clarifai
3
- Version: 11.4.6
3
+ Version: 11.4.7
4
4
  Home-page: https://github.com/Clarifai/clarifai-python
5
5
  Author: Clarifai
6
6
  Author-email: support@clarifai.com
@@ -1,6 +1,5 @@
1
1
  import logging
2
2
  import os
3
- from collections import namedtuple
4
3
 
5
4
  import pytest
6
5
 
@@ -15,8 +14,6 @@ PDF_URL = "https://samples.clarifai.com/test_doc.pdf"
15
14
 
16
15
  CLARIFAI_API_BASE = os.environ.get("CLARIFAI_API_BASE", "https://api.clarifai.com")
17
16
 
18
- auth_obj = namedtuple("auth", "ui")
19
-
20
17
 
21
18
  def client():
22
19
  return User(user_id=CREATE_APP_USER_ID, base_url=CLARIFAI_API_BASE)
@@ -1 +0,0 @@
1
- __version__ = "11.4.6"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes