clarifai 11.4.2__tar.gz → 11.4.3__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.
- {clarifai-11.4.2/clarifai.egg-info → clarifai-11.4.3}/PKG-INFO +1 -1
- clarifai-11.4.3/clarifai/__init__.py +1 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/cli/base.py +7 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/cli/model.py +6 -8
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/client/app.py +2 -1
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/client/auth/helper.py +6 -4
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/client/compute_cluster.py +2 -1
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/client/dataset.py +2 -1
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/client/deployment.py +2 -1
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/client/input.py +2 -1
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/client/model.py +2 -1
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/client/model_client.py +1 -1
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/client/module.py +2 -1
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/client/nodepool.py +2 -1
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/client/runner.py +2 -1
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/client/search.py +2 -1
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/client/user.py +2 -1
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/client/workflow.py +2 -1
- clarifai-11.4.3/clarifai/runners/models/mcp_class.py +114 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/runners/models/model_builder.py +40 -11
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/runners/utils/code_script.py +35 -1
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/runners/utils/data_types/data_types.py +48 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/runners/utils/data_utils.py +66 -40
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/runners/utils/openai_convertor.py +103 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/urls/helper.py +80 -12
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/utils/config.py +19 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/utils/constants.py +4 -0
- {clarifai-11.4.2 → clarifai-11.4.3/clarifai.egg-info}/PKG-INFO +1 -1
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai.egg-info/SOURCES.txt +1 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/tests/test_modules.py +9 -18
- {clarifai-11.4.2 → clarifai-11.4.3}/tests/test_rag.py +1 -2
- clarifai-11.4.2/clarifai/__init__.py +0 -1
- {clarifai-11.4.2 → clarifai-11.4.3}/LICENSE +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/MANIFEST.in +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/README.md +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/cli/README.md +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/cli/__init__.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/cli/__main__.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/cli/compute_cluster.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/cli/deployment.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/cli/nodepool.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/cli.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/client/__init__.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/client/auth/__init__.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/client/auth/register.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/client/auth/stub.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/client/base.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/client/lister.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/constants/base.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/constants/dataset.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/constants/input.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/constants/model.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/constants/rag.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/constants/search.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/constants/workflow.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/datasets/__init__.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/datasets/export/__init__.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/datasets/export/inputs_annotations.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/datasets/upload/__init__.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/datasets/upload/base.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/datasets/upload/features.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/datasets/upload/image.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/datasets/upload/loaders/README.md +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/datasets/upload/loaders/__init__.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/datasets/upload/loaders/coco_captions.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/datasets/upload/loaders/coco_detection.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/datasets/upload/loaders/imagenet_classification.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/datasets/upload/loaders/xview_detection.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/datasets/upload/multimodal.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/datasets/upload/text.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/datasets/upload/utils.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/errors.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/models/__init__.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/models/api.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/modules/README.md +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/modules/__init__.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/modules/css.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/modules/pages.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/modules/style.css +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/rag/__init__.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/rag/rag.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/rag/utils.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/runners/__init__.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/runners/dockerfile_template/Dockerfile.template +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/runners/models/__init__.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/runners/models/model_class.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/runners/models/model_run_locally.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/runners/models/model_runner.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/runners/models/model_servicer.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/runners/models/visual_classifier_class.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/runners/models/visual_detector_class.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/runners/server.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/runners/utils/__init__.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/runners/utils/const.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/runners/utils/data_types/__init__.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/runners/utils/loader.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/runners/utils/method_signatures.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/runners/utils/serializers.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/runners/utils/url_fetcher.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/schema/search.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/utils/__init__.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/utils/cli.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/utils/evaluation/__init__.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/utils/evaluation/helpers.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/utils/evaluation/main.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/utils/evaluation/testset_annotation_parser.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/utils/logging.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/utils/misc.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/utils/model_train.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/utils/protobuf.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/versions.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/workflows/__init__.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/workflows/export.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/workflows/utils.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai/workflows/validate.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai.egg-info/dependency_links.txt +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai.egg-info/entry_points.txt +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai.egg-info/requires.txt +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/clarifai.egg-info/top_level.txt +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/pyproject.toml +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/requirements.txt +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/setup.cfg +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/setup.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/tests/test_app.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/tests/test_auth.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/tests/test_data_upload.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/tests/test_eval.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/tests/test_misc.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/tests/test_model_predict.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/tests/test_model_train.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/tests/test_search.py +0 -0
- {clarifai-11.4.2 → clarifai-11.4.3}/tests/test_stub.py +0 -0
@@ -0,0 +1 @@
|
|
1
|
+
__version__ = "11.4.3"
|
@@ -143,6 +143,13 @@ def dump(ctx_obj, output_format):
|
|
143
143
|
json.dump(ctx_obj.to_dict(), sys.stdout, indent=2)
|
144
144
|
|
145
145
|
|
146
|
+
@config.command(['cat'])
|
147
|
+
@click.pass_obj
|
148
|
+
def env(ctx_obj):
|
149
|
+
"""Print env vars. Use: eval "$(clarifai config env)" """
|
150
|
+
ctx_obj.current.print_env_vars()
|
151
|
+
|
152
|
+
|
146
153
|
@cli.command()
|
147
154
|
@click.argument('api_url', default="https://api.clarifai.com")
|
148
155
|
@click.option('--user_id', required=False, help='User ID')
|
@@ -504,6 +504,10 @@ def local_dev(ctx, model_path):
|
|
504
504
|
|
505
505
|
logger.info(f"Current deployment_id: {deployment_id}")
|
506
506
|
|
507
|
+
logger.info(
|
508
|
+
f"Full url for the model: /users/{user_id}/apps/{app_id}/models/{model.id}/versions/{version.id}"
|
509
|
+
)
|
510
|
+
|
507
511
|
# Now that we have all the context in ctx.obj, we need to update the config.yaml in
|
508
512
|
# the model_path directory with the model object containing user_id, app_id, model_id, version_id
|
509
513
|
config_file = os.path.join(model_path, 'config.yaml')
|
@@ -526,13 +530,9 @@ def local_dev(ctx, model_path):
|
|
526
530
|
ModelBuilder._backup_config(config_file)
|
527
531
|
ModelBuilder._save_config(config_file, config)
|
528
532
|
|
529
|
-
# client_model = Model(
|
530
|
-
# TODO: once we can generate_client_script from ModelBuilder or similar
|
531
|
-
# we should be able to put the exact function call in place.
|
532
|
-
# model_script = model.generate_client_script()
|
533
|
-
|
534
533
|
builder = ModelBuilder(model_path, download_validation_only=True)
|
535
|
-
|
534
|
+
# don't mock for local dev since you need the dependencies to run the code anyways.
|
535
|
+
method_signatures = builder.get_method_signatures(mocking=False)
|
536
536
|
|
537
537
|
from clarifai.runners.utils import code_script
|
538
538
|
|
@@ -546,8 +546,6 @@ def local_dev(ctx, model_path):
|
|
546
546
|
base_url=ctx.obj.current.api_base,
|
547
547
|
)
|
548
548
|
|
549
|
-
# TODO: put in the ClarifaiUrlHelper to create the model url.
|
550
|
-
|
551
549
|
logger.info("""\n
|
552
550
|
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
553
551
|
# About to start up the local dev runner in this terminal...
|
@@ -19,6 +19,7 @@ from clarifai.client.workflow import Workflow
|
|
19
19
|
from clarifai.constants.model import TRAINABLE_MODEL_TYPES
|
20
20
|
from clarifai.errors import UserError
|
21
21
|
from clarifai.urls.helper import ClarifaiUrlHelper
|
22
|
+
from clarifai.utils.constants import DEFAULT_BASE
|
22
23
|
from clarifai.utils.logging import display_concept_relations_tree, display_workflow_tree, logger
|
23
24
|
from clarifai.utils.misc import concept_relations_accumulation
|
24
25
|
from clarifai.workflows.utils import get_yaml_output_info_proto, is_same_yaml_model
|
@@ -33,7 +34,7 @@ class App(Lister, BaseClient):
|
|
33
34
|
url: str = None,
|
34
35
|
app_id: str = None,
|
35
36
|
user_id: str = None,
|
36
|
-
base_url: str =
|
37
|
+
base_url: str = DEFAULT_BASE,
|
37
38
|
pat: str = None,
|
38
39
|
token: str = None,
|
39
40
|
root_certificates_path: str = None,
|
@@ -7,10 +7,12 @@ from clarifai_grpc.channel.clarifai_channel import ClarifaiChannel
|
|
7
7
|
from clarifai_grpc.grpc.api import resources_pb2, service_pb2_grpc
|
8
8
|
|
9
9
|
from clarifai import __version__
|
10
|
-
from clarifai.utils.constants import
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
from clarifai.utils.constants import (
|
11
|
+
CLARIFAI_PAT_ENV_VAR,
|
12
|
+
CLARIFAI_SESSION_TOKEN_ENV_VAR,
|
13
|
+
DEFAULT_BASE,
|
14
|
+
DEFAULT_UI,
|
15
|
+
)
|
14
16
|
|
15
17
|
REQUEST_ID_PREFIX_HEADER = "x-clarifai-request-id-prefix"
|
16
18
|
REQUEST_ID_PREFIX = f"sdk-python-{__version__}"
|
@@ -10,6 +10,7 @@ from clarifai.client.base import BaseClient
|
|
10
10
|
from clarifai.client.lister import Lister
|
11
11
|
from clarifai.client.nodepool import Nodepool
|
12
12
|
from clarifai.errors import UserError
|
13
|
+
from clarifai.utils.constants import DEFAULT_BASE
|
13
14
|
from clarifai.utils.logging import logger
|
14
15
|
|
15
16
|
|
@@ -20,7 +21,7 @@ class ComputeCluster(Lister, BaseClient):
|
|
20
21
|
self,
|
21
22
|
compute_cluster_id: str = None,
|
22
23
|
user_id: str = None,
|
23
|
-
base_url: str =
|
24
|
+
base_url: str = DEFAULT_BASE,
|
24
25
|
pat: str = None,
|
25
26
|
token: str = None,
|
26
27
|
root_certificates_path: str = None,
|
@@ -45,6 +45,7 @@ ClarifaiDatasetType = TypeVar(
|
|
45
45
|
VisualSegmentationDataset,
|
46
46
|
TextClassificationDataset,
|
47
47
|
)
|
48
|
+
from clarifai.utils.constants import DEFAULT_BASE
|
48
49
|
|
49
50
|
|
50
51
|
class Dataset(Lister, BaseClient):
|
@@ -55,7 +56,7 @@ class Dataset(Lister, BaseClient):
|
|
55
56
|
url: str = None,
|
56
57
|
dataset_id: str = None,
|
57
58
|
dataset_version_id: str = None,
|
58
|
-
base_url: str =
|
59
|
+
base_url: str = DEFAULT_BASE,
|
59
60
|
pat: str = None,
|
60
61
|
token: str = None,
|
61
62
|
root_certificates_path: str = None,
|
@@ -2,6 +2,7 @@ from clarifai_grpc.grpc.api import resources_pb2
|
|
2
2
|
|
3
3
|
from clarifai.client.base import BaseClient
|
4
4
|
from clarifai.client.lister import Lister
|
5
|
+
from clarifai.utils.constants import DEFAULT_BASE
|
5
6
|
from clarifai.utils.logging import logger
|
6
7
|
from clarifai.utils.protobuf import dict_to_protobuf
|
7
8
|
|
@@ -13,7 +14,7 @@ class Deployment(Lister, BaseClient):
|
|
13
14
|
self,
|
14
15
|
deployment_id: str = None,
|
15
16
|
user_id: str = None,
|
16
|
-
base_url: str =
|
17
|
+
base_url: str = DEFAULT_BASE,
|
17
18
|
pat: str = None,
|
18
19
|
token: str = None,
|
19
20
|
root_certificates_path: str = None,
|
@@ -21,6 +21,7 @@ from clarifai.client.lister import Lister
|
|
21
21
|
from clarifai.constants.dataset import MAX_RETRIES
|
22
22
|
from clarifai.constants.input import MAX_UPLOAD_BATCH_SIZE
|
23
23
|
from clarifai.errors import UserError
|
24
|
+
from clarifai.utils.constants import DEFAULT_BASE
|
24
25
|
from clarifai.utils.logging import logger
|
25
26
|
from clarifai.utils.misc import BackoffIterator, Chunker, clean_input_id
|
26
27
|
|
@@ -33,7 +34,7 @@ class Inputs(Lister, BaseClient):
|
|
33
34
|
user_id: str = None,
|
34
35
|
app_id: str = None,
|
35
36
|
logger_level: str = "INFO",
|
36
|
-
base_url: str =
|
37
|
+
base_url: str = DEFAULT_BASE,
|
37
38
|
pat: str = None,
|
38
39
|
token: str = None,
|
39
40
|
root_certificates_path: str = None,
|
@@ -34,6 +34,7 @@ from clarifai.constants.model import (
|
|
34
34
|
)
|
35
35
|
from clarifai.errors import UserError
|
36
36
|
from clarifai.urls.helper import ClarifaiUrlHelper
|
37
|
+
from clarifai.utils.constants import DEFAULT_BASE
|
37
38
|
from clarifai.utils.logging import logger
|
38
39
|
from clarifai.utils.misc import BackoffIterator
|
39
40
|
from clarifai.utils.model_train import (
|
@@ -58,7 +59,7 @@ class Model(Lister, BaseClient):
|
|
58
59
|
url: str = None,
|
59
60
|
model_id: str = None,
|
60
61
|
model_version: Dict = {'id': ""},
|
61
|
-
base_url: str =
|
62
|
+
base_url: str = DEFAULT_BASE,
|
62
63
|
pat: str = None,
|
63
64
|
token: str = None,
|
64
65
|
root_certificates_path: str = None,
|
@@ -8,7 +8,6 @@ from clarifai_grpc.grpc.api.status import status_code_pb2
|
|
8
8
|
from clarifai.constants.model import MAX_MODEL_PREDICT_INPUTS
|
9
9
|
from clarifai.errors import UserError
|
10
10
|
from clarifai.runners.utils import code_script, method_signatures
|
11
|
-
from clarifai.runners.utils.data_utils import is_openai_chat_format
|
12
11
|
from clarifai.runners.utils.method_signatures import (
|
13
12
|
CompatibilitySerializer,
|
14
13
|
deserialize,
|
@@ -16,6 +15,7 @@ from clarifai.runners.utils.method_signatures import (
|
|
16
15
|
serialize,
|
17
16
|
signatures_from_json,
|
18
17
|
)
|
18
|
+
from clarifai.runners.utils.openai_convertor import is_openai_chat_format
|
19
19
|
from clarifai.utils.logging import logger
|
20
20
|
from clarifai.utils.misc import BackoffIterator, status_is_retryable
|
21
21
|
|
@@ -6,6 +6,7 @@ from clarifai.client.base import BaseClient
|
|
6
6
|
from clarifai.client.lister import Lister
|
7
7
|
from clarifai.errors import UserError
|
8
8
|
from clarifai.urls.helper import ClarifaiUrlHelper
|
9
|
+
from clarifai.utils.constants import DEFAULT_BASE
|
9
10
|
from clarifai.utils.logging import logger
|
10
11
|
|
11
12
|
|
@@ -17,7 +18,7 @@ class Module(Lister, BaseClient):
|
|
17
18
|
url: str = None,
|
18
19
|
module_id: str = None,
|
19
20
|
module_version: Dict = {'id': ""},
|
20
|
-
base_url: str =
|
21
|
+
base_url: str = DEFAULT_BASE,
|
21
22
|
pat: str = None,
|
22
23
|
token: str = None,
|
23
24
|
root_certificates_path: str = None,
|
@@ -11,6 +11,7 @@ from clarifai.client.deployment import Deployment
|
|
11
11
|
from clarifai.client.lister import Lister
|
12
12
|
from clarifai.client.runner import Runner
|
13
13
|
from clarifai.errors import UserError
|
14
|
+
from clarifai.utils.constants import DEFAULT_BASE
|
14
15
|
from clarifai.utils.logging import logger
|
15
16
|
|
16
17
|
|
@@ -21,7 +22,7 @@ class Nodepool(Lister, BaseClient):
|
|
21
22
|
self,
|
22
23
|
nodepool_id: str = None,
|
23
24
|
user_id: str = None,
|
24
|
-
base_url: str =
|
25
|
+
base_url: str = DEFAULT_BASE,
|
25
26
|
pat: str = None,
|
26
27
|
token: str = None,
|
27
28
|
root_certificates_path: str = None,
|
@@ -2,6 +2,7 @@ from clarifai_grpc.grpc.api import resources_pb2
|
|
2
2
|
|
3
3
|
from clarifai.client.base import BaseClient
|
4
4
|
from clarifai.client.lister import Lister
|
5
|
+
from clarifai.utils.constants import DEFAULT_BASE
|
5
6
|
from clarifai.utils.logging import logger
|
6
7
|
from clarifai.utils.protobuf import dict_to_protobuf
|
7
8
|
|
@@ -13,7 +14,7 @@ class Runner(Lister, BaseClient):
|
|
13
14
|
self,
|
14
15
|
runner_id: str = None,
|
15
16
|
user_id: str = None,
|
16
|
-
base_url: str =
|
17
|
+
base_url: str = DEFAULT_BASE,
|
17
18
|
pat: str = None,
|
18
19
|
token: str = None,
|
19
20
|
root_certificates_path: str = None,
|
@@ -17,6 +17,7 @@ from clarifai.constants.search import (
|
|
17
17
|
)
|
18
18
|
from clarifai.errors import UserError
|
19
19
|
from clarifai.schema.search import get_schema
|
20
|
+
from clarifai.utils.constants import DEFAULT_BASE
|
20
21
|
|
21
22
|
|
22
23
|
class Search(Lister, BaseClient):
|
@@ -28,7 +29,7 @@ class Search(Lister, BaseClient):
|
|
28
29
|
metric: str = DEFAULT_SEARCH_METRIC,
|
29
30
|
algorithm: str = DEFAULT_SEARCH_ALGORITHM,
|
30
31
|
pagination: bool = False,
|
31
|
-
base_url: str =
|
32
|
+
base_url: str = DEFAULT_BASE,
|
32
33
|
pat: str = None,
|
33
34
|
token: str = None,
|
34
35
|
root_certificates_path: str = None,
|
@@ -12,6 +12,7 @@ from clarifai.client.base import BaseClient
|
|
12
12
|
from clarifai.client.compute_cluster import ComputeCluster
|
13
13
|
from clarifai.client.lister import Lister
|
14
14
|
from clarifai.errors import UserError
|
15
|
+
from clarifai.utils.constants import DEFAULT_BASE
|
15
16
|
from clarifai.utils.logging import logger
|
16
17
|
|
17
18
|
|
@@ -21,7 +22,7 @@ class User(Lister, BaseClient):
|
|
21
22
|
def __init__(
|
22
23
|
self,
|
23
24
|
user_id: str = None,
|
24
|
-
base_url: str =
|
25
|
+
base_url: str = DEFAULT_BASE,
|
25
26
|
pat: str = None,
|
26
27
|
token: str = None,
|
27
28
|
root_certificates_path: str = None,
|
@@ -14,6 +14,7 @@ from clarifai.client.model import Model
|
|
14
14
|
from clarifai.constants.workflow import MAX_WORKFLOW_PREDICT_INPUTS
|
15
15
|
from clarifai.errors import UserError
|
16
16
|
from clarifai.urls.helper import ClarifaiUrlHelper
|
17
|
+
from clarifai.utils.constants import DEFAULT_BASE
|
17
18
|
from clarifai.utils.logging import logger
|
18
19
|
from clarifai.utils.misc import BackoffIterator, status_is_retryable
|
19
20
|
from clarifai.workflows.export import Exporter
|
@@ -28,7 +29,7 @@ class Workflow(Lister, BaseClient):
|
|
28
29
|
workflow_id: str = None,
|
29
30
|
workflow_version: Dict = {'id': ""},
|
30
31
|
output_config: Dict = {'min_value': 0},
|
31
|
-
base_url: str =
|
32
|
+
base_url: str = DEFAULT_BASE,
|
32
33
|
pat: str = None,
|
33
34
|
token: str = None,
|
34
35
|
root_certificates_path: str = None,
|
@@ -0,0 +1,114 @@
|
|
1
|
+
"""Base class for creating Model Context Protocol (MCP) servers."""
|
2
|
+
|
3
|
+
import asyncio
|
4
|
+
import json
|
5
|
+
from typing import Any
|
6
|
+
|
7
|
+
from fastmcp import Client, FastMCP # use fastmcp v2 not the built in mcp
|
8
|
+
from mcp import types
|
9
|
+
from mcp.shared.exceptions import McpError
|
10
|
+
|
11
|
+
from clarifai.runners.models.model_class import ModelClass
|
12
|
+
|
13
|
+
|
14
|
+
class MCPModelClass(ModelClass):
|
15
|
+
"""Base class for wrapping FastMCP servers as a model running in Clarfai. This handles
|
16
|
+
all the transport between the API and the MCP server here. Simply subclass this and implement
|
17
|
+
the get_server() method to return the FastMCP server instance. The server is then used to
|
18
|
+
handle all the requests and responses.
|
19
|
+
"""
|
20
|
+
|
21
|
+
def load_model(self):
|
22
|
+
# in memory transport provided in fastmcp v2 so we can easily use the client functions.
|
23
|
+
self.client = Client(self.get_server())
|
24
|
+
|
25
|
+
def get_server(self) -> FastMCP:
|
26
|
+
"""Required method for each subclass to implement to return the FastMCP server to use."""
|
27
|
+
raise NotImplementedError("Subclasses must implement get_server() method")
|
28
|
+
|
29
|
+
@ModelClass.method
|
30
|
+
def mcp_transport(self, msg: str) -> str:
|
31
|
+
"""The single model method to get the jsonrpc message and send it to the FastMCP server then
|
32
|
+
return it's response.
|
33
|
+
|
34
|
+
"""
|
35
|
+
|
36
|
+
async def send_notification(client_message: types.ClientNotification) -> None:
|
37
|
+
async with self.client:
|
38
|
+
# Strip the jsonrpc field since send_notification will also pass it in for some reason.
|
39
|
+
client_message = types.ClientNotification.model_validate(
|
40
|
+
client_message.model_dump(
|
41
|
+
by_alias=True, mode="json", exclude_none=True, exclude={"jsonrpc"}
|
42
|
+
)
|
43
|
+
)
|
44
|
+
try:
|
45
|
+
return await self.client.session.send_notification(client_message)
|
46
|
+
except McpError as e:
|
47
|
+
return types.JSONRPCError(jsonrpc="2.0", error=e.error)
|
48
|
+
|
49
|
+
async def send_request(client_message: types.ClientRequest, id: str) -> Any:
|
50
|
+
async with self.client:
|
51
|
+
# Strip the jsonrpc and id fields as send_request sets them again too.
|
52
|
+
client_message = types.ClientRequest.model_validate(
|
53
|
+
client_message.model_dump(
|
54
|
+
by_alias=True, mode="json", exclude_none=True, exclude={"jsonrpc", "id"}
|
55
|
+
)
|
56
|
+
)
|
57
|
+
|
58
|
+
result_type = None
|
59
|
+
if isinstance(client_message.root, types.PingRequest):
|
60
|
+
result_type = types.EmptyResult
|
61
|
+
elif isinstance(client_message.root, types.InitializeRequest):
|
62
|
+
return await self.client.session.initialize()
|
63
|
+
elif isinstance(client_message.root, types.SetLevelRequest):
|
64
|
+
result_type = types.EmptyResult
|
65
|
+
elif isinstance(client_message.root, types.ListResourcesRequest):
|
66
|
+
result_type = types.ListResourcesResult
|
67
|
+
elif isinstance(client_message.root, types.ListResourceTemplatesRequest):
|
68
|
+
result_type = types.ListResourceTemplatesResult
|
69
|
+
elif isinstance(client_message.root, types.ReadResourceRequest):
|
70
|
+
result_type = types.ReadResourceResult
|
71
|
+
elif isinstance(client_message.root, types.SubscribeRequest):
|
72
|
+
result_type = types.EmptyResult
|
73
|
+
elif isinstance(client_message.root, types.UnsubscribeRequest):
|
74
|
+
result_type = types.EmptyResult
|
75
|
+
elif isinstance(client_message.root, types.ListPromptsRequest):
|
76
|
+
result_type = types.ListPromptsResult
|
77
|
+
elif isinstance(client_message.root, types.GetPromptRequest):
|
78
|
+
result_type = types.GetPromptResult
|
79
|
+
elif isinstance(client_message.root, types.CompleteRequest):
|
80
|
+
result_type = types.CompleteResult
|
81
|
+
elif isinstance(client_message.root, types.ListToolsRequest):
|
82
|
+
result_type = types.ListToolsResult
|
83
|
+
elif isinstance(client_message.root, types.CallToolRequest):
|
84
|
+
result_type = types.CallToolResult
|
85
|
+
else:
|
86
|
+
# this is a special case where we need to return the list of tools.
|
87
|
+
raise NotImplementedError(f"Method {client_message.method} not implemented")
|
88
|
+
# Call the mcp server using send_request() or send_notification() depending on the method.
|
89
|
+
try:
|
90
|
+
return await self.client.session.send_request(client_message, result_type)
|
91
|
+
except McpError as e:
|
92
|
+
return types.JSONRPCError(jsonrpc="2.0", id=id, error=e.error)
|
93
|
+
|
94
|
+
# The message coming here is the generic request. We look at it's .method
|
95
|
+
# to determine which client function to call and to further subparse the params.
|
96
|
+
# Note(zeiler): unfortunately the pydantic types in mcp/types.py are not consistent.
|
97
|
+
# The JSONRPCRequest are supposed to have an id but the InitializeRequest
|
98
|
+
# does not have it.
|
99
|
+
d = json.loads(msg)
|
100
|
+
id = d.get('id', "")
|
101
|
+
|
102
|
+
# If we have an id it's a JSONRPCRequest
|
103
|
+
if not d.get('method', '').startswith("notifications/"):
|
104
|
+
client_message = types.ClientRequest.model_validate(d)
|
105
|
+
response = asyncio.run(send_request(client_message, id=id))
|
106
|
+
else: # JSONRPCRequest
|
107
|
+
client_message = types.ClientNotification.model_validate(d)
|
108
|
+
response = asyncio.run(send_notification(client_message))
|
109
|
+
if response is None:
|
110
|
+
response = types.JSONRPCError(
|
111
|
+
jsonrpc="2.0", id=id, error="Got empty response from MCP server."
|
112
|
+
)
|
113
|
+
# return as a serialized json string
|
114
|
+
return response.model_dump_json(by_alias=True, exclude_none=True)
|
@@ -410,11 +410,17 @@ class ModelBuilder:
|
|
410
410
|
signatures = {method.name: method.signature for method in method_info.values()}
|
411
411
|
return signatures_to_yaml(signatures)
|
412
412
|
|
413
|
-
def get_method_signatures(self):
|
413
|
+
def get_method_signatures(self, mocking=True):
|
414
414
|
"""
|
415
415
|
Returns the method signatures for the model class.
|
416
|
+
|
417
|
+
Args:
|
418
|
+
mocking (bool): Whether to mock the model class or not. Defaults to False.
|
419
|
+
|
420
|
+
Returns:
|
421
|
+
list: A list of method signatures for the model class.
|
416
422
|
"""
|
417
|
-
model_class = self.load_model_class(mocking=
|
423
|
+
model_class = self.load_model_class(mocking=mocking)
|
418
424
|
method_info = model_class._get_method_info()
|
419
425
|
signatures = [method.signature for method in method_info.values()]
|
420
426
|
return signatures
|
@@ -436,22 +442,42 @@ class ModelBuilder:
|
|
436
442
|
return self._client
|
437
443
|
|
438
444
|
@property
|
439
|
-
def
|
445
|
+
def model_ui_url(self):
|
446
|
+
url_helper = ClarifaiUrlHelper(self._client.auth_helper)
|
447
|
+
# Note(zeiler): the UI experience isn't the best when including version id right now.
|
448
|
+
# if self.model_version_id is not None:
|
449
|
+
# return url_helper.clarifai_url(
|
450
|
+
# self.client.user_app_id.user_id,
|
451
|
+
# self.client.user_app_id.app_id,
|
452
|
+
# "models",
|
453
|
+
# self.model_id,
|
454
|
+
# self.model_version_id,
|
455
|
+
# )
|
456
|
+
# else:
|
457
|
+
return url_helper.clarifai_url(
|
458
|
+
self.client.user_app_id.user_id,
|
459
|
+
self.client.user_app_id.app_id,
|
460
|
+
"models",
|
461
|
+
self.model_id,
|
462
|
+
)
|
463
|
+
|
464
|
+
@property
|
465
|
+
def model_api_url(self):
|
440
466
|
url_helper = ClarifaiUrlHelper(self._client.auth_helper)
|
441
467
|
if self.model_version_id is not None:
|
442
|
-
return url_helper.
|
468
|
+
return url_helper.api_url(
|
443
469
|
self.client.user_app_id.user_id,
|
444
470
|
self.client.user_app_id.app_id,
|
445
471
|
"models",
|
446
472
|
self.model_id,
|
473
|
+
self.model_version_id,
|
447
474
|
)
|
448
475
|
else:
|
449
|
-
return url_helper.
|
476
|
+
return url_helper.api_url(
|
450
477
|
self.client.user_app_id.user_id,
|
451
478
|
self.client.user_app_id.app_id,
|
452
479
|
"models",
|
453
480
|
self.model_id,
|
454
|
-
self.model_version_id,
|
455
481
|
)
|
456
482
|
|
457
483
|
def _get_model_proto(self):
|
@@ -930,10 +956,11 @@ class ModelBuilder:
|
|
930
956
|
return
|
931
957
|
self.model_version_id = response.model_version_id
|
932
958
|
logger.info(f"Created Model Version ID: {self.model_version_id}")
|
933
|
-
logger.info(f"Full url to that version is: {self.
|
959
|
+
logger.info(f"Full url to that version is: {self.model_ui_url}")
|
934
960
|
try:
|
935
961
|
is_uploaded = self.monitor_model_build()
|
936
962
|
if is_uploaded:
|
963
|
+
# python code to run the model.
|
937
964
|
from clarifai.runners.utils import code_script
|
938
965
|
|
939
966
|
method_signatures = self.get_method_signatures()
|
@@ -945,7 +972,7 @@ class ModelBuilder:
|
|
945
972
|
)
|
946
973
|
logger.info("""\n
|
947
974
|
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
948
|
-
# Here is a code snippet to
|
975
|
+
# Here is a code snippet to use this model:
|
949
976
|
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
950
977
|
""")
|
951
978
|
logger.info(snippet)
|
@@ -1049,7 +1076,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
|
1049
1076
|
logger.info("Model build complete!")
|
1050
1077
|
logger.info(f"Build time elapsed {time.time() - st:.1f}s)")
|
1051
1078
|
logger.info(
|
1052
|
-
f"Check out the model at {self.
|
1079
|
+
f"Check out the model at {self.model_ui_url} version: {self.model_version_id}"
|
1053
1080
|
)
|
1054
1081
|
return True
|
1055
1082
|
else:
|
@@ -1074,10 +1101,12 @@ def upload_model(folder, stage, skip_dockerfile):
|
|
1074
1101
|
exists = builder.check_model_exists()
|
1075
1102
|
if exists:
|
1076
1103
|
logger.info(
|
1077
|
-
f"Model already exists at {builder.
|
1104
|
+
f"Model already exists at {builder.model_ui_url}, this upload will create a new version for it."
|
1078
1105
|
)
|
1079
1106
|
else:
|
1080
|
-
logger.info(
|
1107
|
+
logger.info(
|
1108
|
+
f"New model will be created at {builder.model_ui_url} with it's first version."
|
1109
|
+
)
|
1081
1110
|
|
1082
1111
|
input("Press Enter to continue...")
|
1083
1112
|
builder.upload_model_version()
|
@@ -4,6 +4,7 @@ from typing import List
|
|
4
4
|
from clarifai_grpc.grpc.api import resources_pb2
|
5
5
|
|
6
6
|
from clarifai.runners.utils import data_utils
|
7
|
+
from clarifai.urls.helper import ClarifaiUrlHelper
|
7
8
|
|
8
9
|
|
9
10
|
def generate_client_script(
|
@@ -15,6 +16,38 @@ def generate_client_script(
|
|
15
16
|
deployment_id: str = None,
|
16
17
|
use_ctx: bool = False,
|
17
18
|
) -> str:
|
19
|
+
url_helper = ClarifaiUrlHelper()
|
20
|
+
|
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(
|
24
|
+
user_id,
|
25
|
+
app_id,
|
26
|
+
"models",
|
27
|
+
model_id,
|
28
|
+
)
|
29
|
+
|
30
|
+
_CLIENT_TEMPLATE = """
|
31
|
+
import asyncio
|
32
|
+
import os
|
33
|
+
from fastmcp import Client
|
34
|
+
from fastmcp.client.transports import StreamableHttpTransport
|
35
|
+
|
36
|
+
transport = StreamableHttpTransport(url="%s/mcp",
|
37
|
+
headers={"Authorization": "Bearer " + os.environ["CLARIFAI_PAT"]})
|
38
|
+
|
39
|
+
async def main():
|
40
|
+
async with Client(transport) as client:
|
41
|
+
tools = await client.list_tools()
|
42
|
+
print(f"Available tools: {tools}")
|
43
|
+
result = await client.call_tool(tools[0].name, {"a": 5, "b": 3})
|
44
|
+
print(f"Result: {result[0].text}")
|
45
|
+
|
46
|
+
if __name__ == "__main__":
|
47
|
+
asyncio.run(main())
|
48
|
+
"""
|
49
|
+
return _CLIENT_TEMPLATE % api_url
|
50
|
+
|
18
51
|
_CLIENT_TEMPLATE = """\
|
19
52
|
import os
|
20
53
|
|
@@ -35,8 +68,9 @@ from clarifai.runners.utils import data_types
|
|
35
68
|
model_section = """
|
36
69
|
model = Model.from_current_context()"""
|
37
70
|
else:
|
71
|
+
model_ui_url = url_helper.clarifai_url(user_id, app_id, "models", model_id)
|
38
72
|
model_section = f"""
|
39
|
-
model = Model(
|
73
|
+
model = Model({model_ui_url},
|
40
74
|
deployment_id = {deployment_id}, # Only needed for dedicated deployed models
|
41
75
|
{base_url_str}
|
42
76
|
)
|
@@ -395,6 +395,22 @@ class Image(MessageData):
|
|
395
395
|
raise ValueError("Image has no bytes")
|
396
396
|
return PILImage.open(io.BytesIO(self.proto.base64))
|
397
397
|
|
398
|
+
def to_base64_str(self) -> str:
|
399
|
+
if not self.proto.base64:
|
400
|
+
raise ValueError("Image has no bytes")
|
401
|
+
if isinstance(self.proto.base64, str):
|
402
|
+
return self.proto.base64
|
403
|
+
if isinstance(self.proto.base64, bytes):
|
404
|
+
try:
|
405
|
+
# trying direct decode (if already a base64 bytes)
|
406
|
+
return self.proto.base64.decode('utf-8')
|
407
|
+
except UnicodeDecodeError:
|
408
|
+
import base64
|
409
|
+
|
410
|
+
return base64.b64encode(self.proto.base64).decode('utf-8')
|
411
|
+
else:
|
412
|
+
raise TypeError("Expected str or bytes for Image.base64")
|
413
|
+
|
398
414
|
def to_numpy(self) -> np.ndarray:
|
399
415
|
return np.asarray(self.to_pil())
|
400
416
|
|
@@ -466,6 +482,22 @@ class Audio(MessageData):
|
|
466
482
|
def to_proto(self) -> AudioProto:
|
467
483
|
return self.proto
|
468
484
|
|
485
|
+
def to_base64_str(self) -> str:
|
486
|
+
if not self.proto.base64:
|
487
|
+
raise ValueError("Audio has no bytes")
|
488
|
+
if isinstance(self.proto.base64, str):
|
489
|
+
return self.proto.base64
|
490
|
+
if isinstance(self.proto.base64, bytes):
|
491
|
+
try:
|
492
|
+
# trying direct decode (if already a base64 bytes)
|
493
|
+
return self.proto.base64.decode('utf-8')
|
494
|
+
except UnicodeDecodeError:
|
495
|
+
import base64
|
496
|
+
|
497
|
+
return base64.b64encode(self.proto.base64).decode('utf-8')
|
498
|
+
else:
|
499
|
+
raise TypeError("Expected str or bytes for Audio.base64")
|
500
|
+
|
469
501
|
@classmethod
|
470
502
|
def from_proto(cls, proto: AudioProto) -> "Audio":
|
471
503
|
return cls(proto)
|
@@ -578,6 +610,22 @@ class Video(MessageData):
|
|
578
610
|
def to_proto(self) -> VideoProto:
|
579
611
|
return self.proto
|
580
612
|
|
613
|
+
def to_base64_str(self) -> str:
|
614
|
+
if not self.proto.base64:
|
615
|
+
raise ValueError("Video has no bytes")
|
616
|
+
if isinstance(self.proto.base64, str):
|
617
|
+
return self.proto.base64
|
618
|
+
if isinstance(self.proto.base64, bytes):
|
619
|
+
try:
|
620
|
+
# trying direct decode (if already a base64 bytes)
|
621
|
+
return self.proto.base64.decode('utf-8')
|
622
|
+
except UnicodeDecodeError:
|
623
|
+
import base64
|
624
|
+
|
625
|
+
return base64.b64encode(self.proto.base64).decode('utf-8')
|
626
|
+
else:
|
627
|
+
raise TypeError("Expected str or bytes for Video.base64")
|
628
|
+
|
581
629
|
@classmethod
|
582
630
|
def from_proto(cls, proto: VideoProto) -> "Video":
|
583
631
|
return cls(proto)
|