clarifai 10.5.4__py3-none-any.whl → 10.8.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- clarifai/__init__.py +1 -0
- clarifai/client/app.py +274 -27
- clarifai/client/base.py +5 -0
- clarifai/client/model.py +6 -1
- clarifai/client/search.py +28 -42
- clarifai/client/user.py +33 -0
- clarifai/datasets/export/inputs_annotations.py +1 -1
- clarifai/utils/logging.py +14 -1
- clarifai/utils/misc.py +24 -1
- clarifai/versions.py +2 -1
- {clarifai-10.5.4.dist-info → clarifai-10.8.0.dist-info}/METADATA +2 -2
- {clarifai-10.5.4.dist-info → clarifai-10.8.0.dist-info}/RECORD +16 -16
- {clarifai-10.5.4.dist-info → clarifai-10.8.0.dist-info}/WHEEL +1 -1
- {clarifai-10.5.4.dist-info → clarifai-10.8.0.dist-info}/LICENSE +0 -0
- {clarifai-10.5.4.dist-info → clarifai-10.8.0.dist-info}/entry_points.txt +0 -0
- {clarifai-10.5.4.dist-info → clarifai-10.8.0.dist-info}/top_level.txt +0 -0
clarifai/__init__.py
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
__version__ = "10.8.0"
|
clarifai/client/app.py
CHANGED
@@ -4,7 +4,7 @@ from typing import Any, Dict, Generator, List
|
|
4
4
|
|
5
5
|
import yaml
|
6
6
|
from clarifai_grpc.grpc.api import resources_pb2, service_pb2
|
7
|
-
from clarifai_grpc.grpc.api.resources_pb2 import Concept
|
7
|
+
from clarifai_grpc.grpc.api.resources_pb2 import Concept, ConceptRelation
|
8
8
|
from clarifai_grpc.grpc.api.status import status_code_pb2
|
9
9
|
from google.protobuf.json_format import MessageToDict
|
10
10
|
|
@@ -19,7 +19,9 @@ 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.logging import display_workflow_tree,
|
22
|
+
from clarifai.utils.logging import (display_concept_relations_tree, display_workflow_tree,
|
23
|
+
get_logger)
|
24
|
+
from clarifai.utils.misc import concept_relations_accumulation
|
23
25
|
from clarifai.workflows.utils import get_yaml_output_info_proto, is_same_yaml_model
|
24
26
|
from clarifai.workflows.validate import validate
|
25
27
|
|
@@ -258,6 +260,26 @@ class App(Lister, BaseClient):
|
|
258
260
|
yield Module.from_auth_helper(
|
259
261
|
auth=self.auth_helper, module_id=imv_info['module_version']['module_id'], **imv_info)
|
260
262
|
|
263
|
+
def get_input_count(self) -> int:
|
264
|
+
"""Get count of all the inputs in the app.
|
265
|
+
|
266
|
+
Returns:
|
267
|
+
input_count: count of inputs in the app.
|
268
|
+
|
269
|
+
Example:
|
270
|
+
>>> from clarifai.client.app import App
|
271
|
+
>>> app = App(app_id="app_id", user_id="user_id")
|
272
|
+
>>> input_count = app.get_input_count()
|
273
|
+
"""
|
274
|
+
request = service_pb2.GetInputCountRequest(user_app_id=self.user_app_id)
|
275
|
+
response = self._grpc_request(self.STUB.GetInputCount, request)
|
276
|
+
|
277
|
+
if response.status.code != status_code_pb2.SUCCESS:
|
278
|
+
raise Exception(response.status)
|
279
|
+
self.logger.info("\nGetting App input Counts\n%s", response.status)
|
280
|
+
|
281
|
+
return response.counts.processed
|
282
|
+
|
261
283
|
def list_concepts(self, page_no: int = None,
|
262
284
|
per_page: int = None) -> Generator[Concept, None, None]:
|
263
285
|
"""Lists all the concepts for the app.
|
@@ -288,6 +310,53 @@ class App(Lister, BaseClient):
|
|
288
310
|
concept_info['id'] = concept_info.pop('concept_id')
|
289
311
|
yield Concept(**concept_info)
|
290
312
|
|
313
|
+
def search_concept_relations(self,
|
314
|
+
concept_id: str = None,
|
315
|
+
predicate: str = None,
|
316
|
+
page_no: int = None,
|
317
|
+
per_page: int = None,
|
318
|
+
show_tree: bool = False) -> Generator[ConceptRelation, None, None]:
|
319
|
+
"""List all the concept relations of the app.
|
320
|
+
|
321
|
+
Args:
|
322
|
+
concept_id (str, optional): The concept ID to filter the concept relations.
|
323
|
+
predicate (str, optional): Type of relation to filter the concept relations. For ex : 'hypernym', 'hyponym' or 'synonym'
|
324
|
+
page_no (int, optional): The page number to list.
|
325
|
+
per_page (int, optional): The number of items per page.
|
326
|
+
show_tree (bool, optional): If True, prints out rich tree representation of concept relations.
|
327
|
+
|
328
|
+
Yields:
|
329
|
+
ConceptRelation: ConceptRelations in the app.
|
330
|
+
|
331
|
+
Example:
|
332
|
+
>>> from clarifai.client.app import App
|
333
|
+
>>> app = App(app_id="app_id", user_id="user_id")
|
334
|
+
>>> all_concept_relations = list(app.search_concept_relations())
|
335
|
+
|
336
|
+
Note:
|
337
|
+
Defaults to 16 per page if page_no is specified and per_page is not specified.
|
338
|
+
If both page_no and per_page are None, then lists all the resources.
|
339
|
+
"""
|
340
|
+
request_data = dict(user_app_id=self.user_app_id, concept_id=concept_id, predicate=predicate)
|
341
|
+
all_concept_relations_infos = self.list_pages_generator(
|
342
|
+
self.STUB.ListConceptRelations,
|
343
|
+
service_pb2.ListConceptRelationsRequest,
|
344
|
+
request_data,
|
345
|
+
per_page=per_page,
|
346
|
+
page_no=page_no)
|
347
|
+
relations_dict = {}
|
348
|
+
for concept_relation_info in all_concept_relations_infos:
|
349
|
+
if show_tree:
|
350
|
+
current_subject_concept = concept_relation_info['subject_concept']['id']
|
351
|
+
current_object_concept = concept_relation_info['object_concept']['id']
|
352
|
+
current_predicate = concept_relation_info['predicate']
|
353
|
+
relations_dict = concept_relations_accumulation(relations_dict, current_subject_concept,
|
354
|
+
current_object_concept, current_predicate)
|
355
|
+
concept_relation_info['id'] = concept_relation_info.pop('concept_relation_id')
|
356
|
+
yield ConceptRelation(**concept_relation_info)
|
357
|
+
if show_tree:
|
358
|
+
display_concept_relations_tree(relations_dict)
|
359
|
+
|
291
360
|
def list_trainable_model_types(self) -> List[str]:
|
292
361
|
"""Lists all the trainable model types.
|
293
362
|
|
@@ -352,33 +421,12 @@ class App(Lister, BaseClient):
|
|
352
421
|
|
353
422
|
return Model.from_auth_helper(auth=self.auth_helper, **kwargs)
|
354
423
|
|
355
|
-
def
|
356
|
-
config_filepath: str,
|
357
|
-
generate_new_id: bool = False,
|
358
|
-
display: bool = True) -> Workflow:
|
359
|
-
"""Creates a workflow for the app.
|
360
|
-
|
361
|
-
Args:
|
362
|
-
config_filepath (str): The path to the yaml workflow config file.
|
363
|
-
generate_new_id (bool): If True, generate a new workflow ID.
|
364
|
-
display (bool): If True, display the workflow nodes tree.
|
365
|
-
|
366
|
-
Returns:
|
367
|
-
Workflow: A Workflow object for the specified workflow config.
|
368
|
-
|
369
|
-
Example:
|
370
|
-
>>> from clarifai.client.app import App
|
371
|
-
>>> app = App(app_id="app_id", user_id="user_id")
|
372
|
-
>>> workflow = app.create_workflow(config_filepath="config.yml")
|
373
|
-
"""
|
374
|
-
if not os.path.exists(config_filepath):
|
375
|
-
raise UserError(f"Workflow config file not found at {config_filepath}")
|
376
|
-
|
424
|
+
def _process_workflow_config(self, config_filepath: str):
|
377
425
|
with open(config_filepath, 'r') as file:
|
378
|
-
|
426
|
+
workflow_config = yaml.safe_load(file)
|
379
427
|
|
380
|
-
|
381
|
-
workflow =
|
428
|
+
workflow_config = validate(workflow_config)
|
429
|
+
workflow = workflow_config['workflow']
|
382
430
|
|
383
431
|
# Get all model objects from the workflow nodes.
|
384
432
|
all_models = []
|
@@ -420,6 +468,32 @@ class App(Lister, BaseClient):
|
|
420
468
|
node.node_inputs.append(resources_pb2.NodeInput(node_id=ni['node_id']))
|
421
469
|
nodes.append(node)
|
422
470
|
|
471
|
+
return workflow, nodes
|
472
|
+
|
473
|
+
def create_workflow(self,
|
474
|
+
config_filepath: str,
|
475
|
+
generate_new_id: bool = False,
|
476
|
+
display: bool = True) -> Workflow:
|
477
|
+
"""Creates a workflow for the app.
|
478
|
+
|
479
|
+
Args:
|
480
|
+
config_filepath (str): The path to the yaml workflow config file.
|
481
|
+
generate_new_id (bool): If True, generate a new workflow ID.
|
482
|
+
display (bool): If True, display the workflow nodes tree.
|
483
|
+
|
484
|
+
Returns:
|
485
|
+
Workflow: A Workflow object for the specified workflow config.
|
486
|
+
|
487
|
+
Example:
|
488
|
+
>>> from clarifai.client.app import App
|
489
|
+
>>> app = App(app_id="app_id", user_id="user_id")
|
490
|
+
>>> workflow = app.create_workflow(config_filepath="config.yml")
|
491
|
+
"""
|
492
|
+
if not os.path.exists(config_filepath):
|
493
|
+
raise UserError(f"Workflow config file not found at {config_filepath}")
|
494
|
+
|
495
|
+
workflow, nodes = self._process_workflow_config(config_filepath)
|
496
|
+
|
423
497
|
workflow_id = workflow['id']
|
424
498
|
if generate_new_id:
|
425
499
|
workflow_id = str(uuid.uuid4())
|
@@ -470,6 +544,60 @@ class App(Lister, BaseClient):
|
|
470
544
|
|
471
545
|
return Module.from_auth_helper(auth=self.auth_helper, module_id=module_id, **kwargs)
|
472
546
|
|
547
|
+
def create_concepts(self, concept_ids: List[str], concepts: List[str] = []) -> None:
|
548
|
+
"""Add concepts to the app.
|
549
|
+
|
550
|
+
Args:
|
551
|
+
concept_ids (List[str]): List of concept IDs of concepts to add to the app.
|
552
|
+
concepts (List[str], optional): List of concepts names of concepts to add to the app.
|
553
|
+
|
554
|
+
Example:
|
555
|
+
>>> from clarifai.client.app import App
|
556
|
+
>>> app = App(app_id="app_id", user_id="user_id")
|
557
|
+
>>> app.add_concepts(concept_ids=["concept_id_1", "concept_id_2", ..])
|
558
|
+
"""
|
559
|
+
if not concepts:
|
560
|
+
concepts = list(concept_ids)
|
561
|
+
concepts_to_add = [
|
562
|
+
resources_pb2.Concept(id=concept_id, name=concept)
|
563
|
+
for concept_id, concept in zip(concept_ids, concepts)
|
564
|
+
]
|
565
|
+
request = service_pb2.PostConceptsRequest(
|
566
|
+
user_app_id=self.user_app_id, concepts=concepts_to_add)
|
567
|
+
response = self._grpc_request(self.STUB.PostConcepts, request)
|
568
|
+
if response.status.code != status_code_pb2.SUCCESS:
|
569
|
+
raise Exception(response.status)
|
570
|
+
self.logger.info("\nConcepts added\n%s", response.status)
|
571
|
+
|
572
|
+
def create_concept_relations(self, subject_concept_id: str, object_concept_ids: List[str],
|
573
|
+
predicates: List[str]) -> None:
|
574
|
+
"""Creates concept relations between concepts of the app.
|
575
|
+
|
576
|
+
Args:
|
577
|
+
subject_concept_id (str): The concept ID of the subject concept.
|
578
|
+
object_concept_ids (List[str]): List of concepts IDs of object concepts.
|
579
|
+
predicates (List[str]): List of predicates corresponding to each relation between subject and objects.
|
580
|
+
|
581
|
+
Example:
|
582
|
+
>>> from clarifai.client.app import App
|
583
|
+
>>> app = App(app_id="app_id", user_id="user_id")
|
584
|
+
>>> app.create_concept_relation(subject_concept_id="subject_concept_id", object_concept_ids=["object_concept_id_1", "object_concept_id_2", ..], predicates=["predicate_1", "predicate_2", ..])
|
585
|
+
"""
|
586
|
+
assert len(object_concept_ids) == len(predicates)
|
587
|
+
subject_relations = [
|
588
|
+
resources_pb2.ConceptRelation(
|
589
|
+
object_concept=resources_pb2.Concept(id=object_concept_id), predicate=predicate)
|
590
|
+
for object_concept_id, predicate in zip(object_concept_ids, predicates)
|
591
|
+
]
|
592
|
+
request = service_pb2.PostConceptRelationsRequest(
|
593
|
+
user_app_id=self.user_app_id,
|
594
|
+
concept_id=subject_concept_id,
|
595
|
+
concept_relations=subject_relations)
|
596
|
+
response = self._grpc_request(self.STUB.PostConceptRelations, request)
|
597
|
+
if response.status.code != status_code_pb2.SUCCESS:
|
598
|
+
raise Exception(response.status)
|
599
|
+
self.logger.info("\nConcept Relations created\n%s", response.status)
|
600
|
+
|
473
601
|
def dataset(self, dataset_id: str, dataset_version_id: str = None, **kwargs) -> Dataset:
|
474
602
|
"""Returns a Dataset object for the existing dataset ID.
|
475
603
|
|
@@ -592,6 +720,100 @@ class App(Lister, BaseClient):
|
|
592
720
|
"""
|
593
721
|
return Inputs.from_auth_helper(self.auth_helper)
|
594
722
|
|
723
|
+
def patch_dataset(self, dataset_id: str, action: str = 'merge', **kwargs) -> Dataset:
|
724
|
+
"""Patches a dataset for the app.
|
725
|
+
|
726
|
+
Args:
|
727
|
+
dataset_id (str): The dataset ID for the dataset to create.
|
728
|
+
action (str): The action to perform on the dataset (merge/overwrite/remove).
|
729
|
+
**kwargs: Additional keyword arguments to be passed to patch the Dataset.
|
730
|
+
|
731
|
+
Returns:
|
732
|
+
Dataset: A Dataset object for the specified dataset ID.
|
733
|
+
"""
|
734
|
+
if "visibility" in kwargs:
|
735
|
+
kwargs["visibility"] = resources_pb2.Visibility(gettable=kwargs["visibility"])
|
736
|
+
if "image_url" in kwargs:
|
737
|
+
kwargs["image"] = resources_pb2.Image(url=kwargs.pop("image_url"))
|
738
|
+
request = service_pb2.PatchDatasetsRequest(
|
739
|
+
user_app_id=self.user_app_id,
|
740
|
+
datasets=[resources_pb2.Dataset(id=dataset_id, **kwargs)],
|
741
|
+
action=action)
|
742
|
+
response = self._grpc_request(self.STUB.PatchDatasets, request)
|
743
|
+
if response.status.code != status_code_pb2.SUCCESS:
|
744
|
+
raise Exception(response.status)
|
745
|
+
self.logger.info("\nDataset patched\n%s", response.status)
|
746
|
+
|
747
|
+
return Dataset.from_auth_helper(self.auth_helper, dataset_id=dataset_id, **kwargs)
|
748
|
+
|
749
|
+
def patch_model(self, model_id: str, action: str = 'merge', **kwargs) -> Model:
|
750
|
+
"""Patches a model of the app.
|
751
|
+
|
752
|
+
Args:
|
753
|
+
model_id (str): The model ID of the model to patch.
|
754
|
+
action (str): The action to perform on the model (merge/overwrite/remove).
|
755
|
+
**kwargs: Additional keyword arguments to be passed to patch the Model.
|
756
|
+
|
757
|
+
Returns:
|
758
|
+
Model: A Model object of the specified model ID.
|
759
|
+
"""
|
760
|
+
if "visibility" in kwargs:
|
761
|
+
kwargs["visibility"] = resources_pb2.Visibility(gettable=kwargs["visibility"])
|
762
|
+
if "image_url" in kwargs:
|
763
|
+
kwargs["image"] = resources_pb2.Image(url=kwargs.pop("image_url"))
|
764
|
+
request = service_pb2.PatchModelsRequest(
|
765
|
+
user_app_id=self.user_app_id,
|
766
|
+
models=[resources_pb2.Model(id=model_id, **kwargs)],
|
767
|
+
action=action)
|
768
|
+
response = self._grpc_request(self.STUB.PatchModels, request)
|
769
|
+
if response.status.code != status_code_pb2.SUCCESS:
|
770
|
+
raise Exception(response.status)
|
771
|
+
self.logger.info("\nModel %s patched successfully\n%s", model_id, response.status)
|
772
|
+
kwargs.update({
|
773
|
+
'model_id': model_id,
|
774
|
+
})
|
775
|
+
|
776
|
+
return Model.from_auth_helper(self.auth_helper, **kwargs)
|
777
|
+
|
778
|
+
def patch_workflow(self,
|
779
|
+
workflow_id: str,
|
780
|
+
action: str = 'merge',
|
781
|
+
config_filepath: str = None,
|
782
|
+
**kwargs) -> Workflow:
|
783
|
+
"""Patches a workflow of the app.
|
784
|
+
|
785
|
+
Args:
|
786
|
+
workflow_id (str): The Workflow ID of the workflow to patch.
|
787
|
+
action (str): The action to perform on the workflow (merge/overwrite/remove).
|
788
|
+
config_filepath (str): The path to the yaml workflow config file.
|
789
|
+
**kwargs: Additional keyword arguments to be passed to patch the Workflow.
|
790
|
+
|
791
|
+
Returns:
|
792
|
+
Workflow: A Workflow object of the specified workflow ID.
|
793
|
+
"""
|
794
|
+
if config_filepath:
|
795
|
+
if not os.path.exists(config_filepath):
|
796
|
+
raise UserError(f"Workflow config file not found at {config_filepath}")
|
797
|
+
_, kwargs['nodes'] = self._process_workflow_config(config_filepath)
|
798
|
+
if "visibility" in kwargs:
|
799
|
+
kwargs["visibility"] = resources_pb2.Visibility(gettable=kwargs["visibility"])
|
800
|
+
if "image_url" in kwargs:
|
801
|
+
kwargs["image"] = resources_pb2.Image(url=kwargs.pop("image_url"))
|
802
|
+
|
803
|
+
request = service_pb2.PatchWorkflowsRequest(
|
804
|
+
user_app_id=self.user_app_id,
|
805
|
+
workflows=[resources_pb2.Workflow(id=workflow_id, **kwargs)],
|
806
|
+
action=action)
|
807
|
+
response = self._grpc_request(self.STUB.PatchWorkflows, request)
|
808
|
+
if response.status.code != status_code_pb2.SUCCESS:
|
809
|
+
raise Exception(response.status)
|
810
|
+
self.logger.info("\nWorkflow patched\n%s", response.status)
|
811
|
+
kwargs.update({
|
812
|
+
'workflow_id': workflow_id,
|
813
|
+
})
|
814
|
+
|
815
|
+
return Workflow.from_auth_helper(self.auth_helper, **kwargs)
|
816
|
+
|
595
817
|
def delete_dataset(self, dataset_id: str) -> None:
|
596
818
|
"""Deletes an dataset for the user.
|
597
819
|
|
@@ -665,6 +887,31 @@ class App(Lister, BaseClient):
|
|
665
887
|
raise Exception(response.status)
|
666
888
|
self.logger.info("\nModule Deleted\n%s", response.status)
|
667
889
|
|
890
|
+
def delete_concept_relations(self, concept_id: str,
|
891
|
+
concept_relation_ids: List[str] = []) -> None:
|
892
|
+
"""Delete concept relations of a concept of the app.
|
893
|
+
|
894
|
+
Args:
|
895
|
+
concept_id (str): The concept ID of the concept to delete relations for.
|
896
|
+
concept_relation_ids (List[str], optional): List of concept relation IDs of concept relations.
|
897
|
+
|
898
|
+
Example:
|
899
|
+
>>> from clarifai.client.app import App
|
900
|
+
>>> app = App(app_id="app_id", user_id="user_id")
|
901
|
+
>>> app.delete_concept_relations(concept_id="concept_id", concept_relation_ids=["concept_relation_id_1", "concept_relation_id_2", ..])
|
902
|
+
"""
|
903
|
+
if not concept_relation_ids:
|
904
|
+
concept_relation_ids = [
|
905
|
+
concept_relation.id
|
906
|
+
for concept_relation in list(self.search_concept_relations(concept_id=concept_id))
|
907
|
+
]
|
908
|
+
request = service_pb2.DeleteConceptRelationsRequest(
|
909
|
+
user_app_id=self.user_app_id, concept_id=concept_id, ids=concept_relation_ids)
|
910
|
+
response = self._grpc_request(self.STUB.DeleteConceptRelations, request)
|
911
|
+
if response.status.code != status_code_pb2.SUCCESS:
|
912
|
+
raise Exception(response.status)
|
913
|
+
self.logger.info("\nConcept Relations Deleted\n%s", response.status)
|
914
|
+
|
668
915
|
def search(self, **kwargs) -> Model:
|
669
916
|
"""Returns a Search object for the user and app ID.
|
670
917
|
|
clarifai/client/base.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
from datetime import datetime
|
2
2
|
from typing import Any, Callable
|
3
3
|
|
4
|
+
from clarifai_grpc.grpc.api import resources_pb2
|
4
5
|
from google.protobuf import struct_pb2
|
5
6
|
from google.protobuf.timestamp_pb2 import Timestamp
|
6
7
|
from google.protobuf.wrappers_pb2 import BoolValue
|
@@ -176,6 +177,10 @@ class BaseClient:
|
|
176
177
|
continue
|
177
178
|
elif key == 'size':
|
178
179
|
value = int(value)
|
180
|
+
elif key == 'image_info':
|
181
|
+
value = resources_pb2.ImageInfo(**value)
|
182
|
+
elif key == 'hosted_image_info':
|
183
|
+
continue
|
179
184
|
elif key in ['metadata']:
|
180
185
|
if isinstance(value, dict) and value != {}:
|
181
186
|
value_s = struct_pb2.Struct()
|
clarifai/client/model.py
CHANGED
@@ -11,6 +11,7 @@ from clarifai_grpc.grpc.api.resources_pb2 import Input
|
|
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
|
14
|
+
from requests.adapters import HTTPAdapter, Retry
|
14
15
|
from tqdm import tqdm
|
15
16
|
|
16
17
|
from clarifai.client.base import BaseClient
|
@@ -1295,7 +1296,11 @@ class Model(Lister, BaseClient):
|
|
1295
1296
|
model_export_url = get_model_export_response.export.url
|
1296
1297
|
model_export_file_size = get_model_export_response.export.size
|
1297
1298
|
|
1298
|
-
|
1299
|
+
session = requests.Session()
|
1300
|
+
retries = Retry(total=10, backoff_factor=1, status_forcelist=[500, 502, 503, 504])
|
1301
|
+
session.mount('https://', HTTPAdapter(max_retries=retries))
|
1302
|
+
session.headers.update({'Authorization': self.metadata[0][1]})
|
1303
|
+
response = session.get(model_export_url, stream=True)
|
1299
1304
|
response.raise_for_status()
|
1300
1305
|
|
1301
1306
|
with open(local_filepath, 'wb') as f:
|
clarifai/client/search.py
CHANGED
@@ -277,7 +277,8 @@ class Search(Lister, BaseClient):
|
|
277
277
|
Get successful inputs of type image or text
|
278
278
|
>>> from clarifai.client.search import Search
|
279
279
|
>>> search = Search(user_id='user_id', app_id='app_id', top_k=10, metric='cosine')
|
280
|
-
|
280
|
+
# This performs OR operation on input_types and input_status_code
|
281
|
+
>>> res = search.query(filters=[{'input_types': ['image', 'text'], 'input_status_code': 30000}])
|
281
282
|
|
282
283
|
Vector search over inputs
|
283
284
|
>>> from clarifai.client.search import Search
|
@@ -298,43 +299,27 @@ class Search(Lister, BaseClient):
|
|
298
299
|
raise UserError(f"Invalid rank or filter input: {err}")
|
299
300
|
|
300
301
|
# For each rank, create a Rank proto message
|
301
|
-
|
302
|
+
# For ranks it only allows resources_pb2.Annotation proto, so no need of splitting protos into annotation and input.
|
303
|
+
all_ranks = []
|
302
304
|
for rank_dict in ranks:
|
303
|
-
rank_annot_proto
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
])
|
322
|
-
if self.pagination:
|
323
|
-
return self._list_all_pages_generator(self.STUB.PostInputsSearches,
|
324
|
-
service_pb2.PostInputsSearchesRequest, request_data,
|
325
|
-
page_no, per_page)
|
326
|
-
return self._list_topk_generator(self.STUB.PostInputsSearches,
|
327
|
-
service_pb2.PostInputsSearchesRequest, request_data)
|
328
|
-
|
329
|
-
# Calls PostAnnotationsSearches for annotation ranks, filters
|
330
|
-
filters_annot_proto = []
|
331
|
-
for filter_dict in filters:
|
332
|
-
filters_annot_proto.append(self._get_annot_proto(**filter_dict))
|
333
|
-
|
334
|
-
all_filters = [
|
335
|
-
resources_pb2.Filter(annotation=filter_annot) for filter_annot in filters_annot_proto
|
336
|
-
]
|
337
|
-
|
305
|
+
rank_annot_proto = self._get_annot_proto(**rank_dict)
|
306
|
+
all_ranks.append(resources_pb2.Rank(annotation=rank_annot_proto))
|
307
|
+
|
308
|
+
all_filters = []
|
309
|
+
# check for filters which is compatible with input proto
|
310
|
+
for each_filter in filters:
|
311
|
+
input_dict = {
|
312
|
+
key: each_filter.pop(key)
|
313
|
+
for key in ['input_types', 'input_dataset_ids', 'input_status_code']
|
314
|
+
if key in each_filter
|
315
|
+
}
|
316
|
+
|
317
|
+
all_filters.append(
|
318
|
+
resources_pb2.Filter(
|
319
|
+
annotation=self._get_annot_proto(**each_filter),
|
320
|
+
input=self._get_input_proto(**input_dict)))
|
321
|
+
|
322
|
+
# Create a PostInputsSearchesRequest proto message
|
338
323
|
request_data = dict(
|
339
324
|
user_app_id=self.user_app_id,
|
340
325
|
searches=[
|
@@ -343,9 +328,10 @@ class Search(Lister, BaseClient):
|
|
343
328
|
algorithm=self.algorithm,
|
344
329
|
metric=self.metric_distance)
|
345
330
|
])
|
331
|
+
# Calls PostInputsSearches for annotation ranks, input filters
|
346
332
|
if self.pagination:
|
347
|
-
return self._list_all_pages_generator(self.STUB.
|
348
|
-
service_pb2.
|
349
|
-
|
350
|
-
return self._list_topk_generator(self.STUB.
|
351
|
-
service_pb2.
|
333
|
+
return self._list_all_pages_generator(self.STUB.PostInputsSearches,
|
334
|
+
service_pb2.PostInputsSearchesRequest, request_data,
|
335
|
+
page_no, per_page)
|
336
|
+
return self._list_topk_generator(self.STUB.PostInputsSearches,
|
337
|
+
service_pb2.PostInputsSearchesRequest, request_data)
|
clarifai/client/user.py
CHANGED
@@ -3,6 +3,7 @@ from typing import Any, Dict, Generator, List
|
|
3
3
|
from clarifai_grpc.grpc.api import resources_pb2, service_pb2
|
4
4
|
from clarifai_grpc.grpc.api.status import status_code_pb2
|
5
5
|
from google.protobuf.json_format import MessageToDict
|
6
|
+
from google.protobuf.wrappers_pb2 import BoolValue
|
6
7
|
|
7
8
|
from clarifai.client.app import App
|
8
9
|
from clarifai.client.base import BaseClient
|
@@ -222,6 +223,38 @@ class User(Lister, BaseClient):
|
|
222
223
|
|
223
224
|
return dict(self.auth_helper, check_runner_exists=False, **kwargs)
|
224
225
|
|
226
|
+
def patch_app(self, app_id: str, action: str = 'overwrite', **kwargs) -> App:
|
227
|
+
"""Patch an app for the user.
|
228
|
+
|
229
|
+
Args:
|
230
|
+
app_id (str): The app ID for the app to patch.
|
231
|
+
action (str): The action to perform on the app (overwrite/remove).
|
232
|
+
**kwargs: Additional keyword arguments to be passed to patch the App.
|
233
|
+
|
234
|
+
Returns:
|
235
|
+
App: Patched App object for the specified app ID.
|
236
|
+
"""
|
237
|
+
if "base_workflow" in kwargs:
|
238
|
+
kwargs["default_workflow"] = resources_pb2.Workflow(
|
239
|
+
id=kwargs.pop("base_workflow"), app_id="main", user_id="clarifai")
|
240
|
+
if "visibility" in kwargs:
|
241
|
+
kwargs["visibility"] = resources_pb2.Visibility(gettable=kwargs["visibility"])
|
242
|
+
if "image_url" in kwargs:
|
243
|
+
kwargs["image"] = resources_pb2.Image(url=kwargs.pop("image_url"))
|
244
|
+
if "is_template" in kwargs:
|
245
|
+
kwargs["is_template"] = BoolValue(value=kwargs["is_template"])
|
246
|
+
request = service_pb2.PatchAppRequest(
|
247
|
+
user_app_id=resources_pb2.UserAppIDSet(user_id=self.id, app_id=app_id),
|
248
|
+
app=resources_pb2.App(id=app_id, **kwargs),
|
249
|
+
action=action,
|
250
|
+
reindex=False)
|
251
|
+
response = self._grpc_request(self.STUB.PatchApp, request)
|
252
|
+
if response.status.code != status_code_pb2.SUCCESS:
|
253
|
+
raise Exception(response.status)
|
254
|
+
self.logger.info("\nApp patched\n%s", response.status)
|
255
|
+
|
256
|
+
return App.from_auth_helper(auth=self.auth_helper, app_id=app_id)
|
257
|
+
|
225
258
|
def delete_app(self, app_id: str) -> None:
|
226
259
|
"""Deletes an app for the user.
|
227
260
|
|
@@ -196,7 +196,7 @@ class InputAnnotationDownloader:
|
|
196
196
|
|
197
197
|
if data_dict.get("concepts") or data_dict.get("regions"):
|
198
198
|
file_name = os.path.join(split, "annotations", input_.id + ".json")
|
199
|
-
annot_data = data_dict.get("
|
199
|
+
annot_data = data_dict.get("regions", []) + data_dict.get("concepts")
|
200
200
|
|
201
201
|
self._save_annotation_to_archive(new_archive, annot_data, file_name)
|
202
202
|
self.num_annotations += 1
|
clarifai/utils/logging.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import logging
|
2
2
|
from collections import defaultdict
|
3
|
-
from typing import Dict, List, Optional, Union
|
3
|
+
from typing import Any, Dict, List, Optional, Union
|
4
4
|
|
5
5
|
from rich import print as rprint
|
6
6
|
from rich.console import Console
|
@@ -138,3 +138,16 @@ def process_log_files(log_file_path: str,) -> tuple:
|
|
138
138
|
return [], []
|
139
139
|
|
140
140
|
return duplicate_input_ids, failed_input_ids
|
141
|
+
|
142
|
+
|
143
|
+
def display_concept_relations_tree(relations_dict: Dict[str, Any]) -> None:
|
144
|
+
"""Print all the concept relations of the app in rich tree format.
|
145
|
+
|
146
|
+
Args:
|
147
|
+
relations_dict (dict): A dict of concept relations info.
|
148
|
+
"""
|
149
|
+
for parent, children in relations_dict.items():
|
150
|
+
tree = Tree(parent)
|
151
|
+
for child in children:
|
152
|
+
tree.add(child)
|
153
|
+
rprint(tree)
|
clarifai/utils/misc.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import os
|
2
|
-
from typing import List
|
2
|
+
from typing import Any, Dict, List
|
3
3
|
|
4
4
|
from clarifai.errors import UserError
|
5
5
|
|
@@ -46,3 +46,26 @@ def get_from_env(key: str, env_key: str) -> str:
|
|
46
46
|
raise UserError(f"Did not find `{key}`, please add an environment variable"
|
47
47
|
f" `{env_key}` which contains it, or pass"
|
48
48
|
f" `{key}` as a named parameter.")
|
49
|
+
|
50
|
+
|
51
|
+
def concept_relations_accumulation(relations_dict: Dict[str, Any], subject_concept: str,
|
52
|
+
object_concept: str, predicate: str) -> Dict[str, Any]:
|
53
|
+
"""Append the concept relation to relations dict based on its predicate.
|
54
|
+
|
55
|
+
Args:
|
56
|
+
relations_dict (dict): A dict of concept relations info.
|
57
|
+
"""
|
58
|
+
if predicate == 'hyponym':
|
59
|
+
if object_concept in relations_dict:
|
60
|
+
relations_dict[object_concept].append(subject_concept)
|
61
|
+
else:
|
62
|
+
relations_dict[object_concept] = [subject_concept]
|
63
|
+
elif predicate == 'hypernym':
|
64
|
+
if subject_concept in relations_dict:
|
65
|
+
relations_dict[subject_concept].append(object_concept)
|
66
|
+
else:
|
67
|
+
relations_dict[subject_concept] = [object_concept]
|
68
|
+
else:
|
69
|
+
relations_dict[object_concept] = []
|
70
|
+
relations_dict[subject_concept] = []
|
71
|
+
return relations_dict
|
clarifai/versions.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: clarifai
|
3
|
-
Version: 10.
|
3
|
+
Version: 10.8.0
|
4
4
|
Summary: Clarifai Python SDK
|
5
5
|
Home-page: https://github.com/Clarifai/clarifai-python
|
6
6
|
Author: Clarifai
|
@@ -20,7 +20,7 @@ Classifier: Operating System :: OS Independent
|
|
20
20
|
Requires-Python: >=3.8
|
21
21
|
Description-Content-Type: text/markdown
|
22
22
|
License-File: LICENSE
|
23
|
-
Requires-Dist: clarifai-grpc >=10.
|
23
|
+
Requires-Dist: clarifai-grpc >=10.8.0
|
24
24
|
Requires-Dist: numpy >=1.22.0
|
25
25
|
Requires-Dist: tqdm >=4.65.0
|
26
26
|
Requires-Dist: tritonclient >=2.34.0
|
@@ -1,17 +1,17 @@
|
|
1
|
-
clarifai/__init__.py,sha256=
|
1
|
+
clarifai/__init__.py,sha256=x_bDnpR_W5o1ETeLzxk1ahCDd3RSOmf0Fs_F69i8AEo,23
|
2
2
|
clarifai/cli.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
3
|
clarifai/errors.py,sha256=RwzTajwds51wLD0MVlMC5kcpBnzRpreDLlazPSBZxrg,2605
|
4
|
-
clarifai/versions.py,sha256=
|
4
|
+
clarifai/versions.py,sha256=jctnczzfGk_S3EnVqb2FjRKfSREkNmvNEwAAa_VoKiQ,222
|
5
5
|
clarifai/client/__init__.py,sha256=xI1U0l5AZdRThvQAXCLsd9axxyFzXXJ22m8LHqVjQRU,662
|
6
|
-
clarifai/client/app.py,sha256=
|
7
|
-
clarifai/client/base.py,sha256=
|
6
|
+
clarifai/client/app.py,sha256=mAUtG5ucNC_MJdyDZi99ttP7R3Tffm6Qp7DahOYo_fE,38531
|
7
|
+
clarifai/client/base.py,sha256=JXbbjg2CXo8rOdw-XgKWWtLVAhPv3OZua5LFT5w4U2Q,7380
|
8
8
|
clarifai/client/dataset.py,sha256=XX-J-9Ict1CQrEycq-JbdxUTuucSgLeDSvnlHE1ucQY,29903
|
9
9
|
clarifai/client/input.py,sha256=ZLqa1jGx4NgCbunOTpJxCq4lDQ5xAf4GQ0rsZY8AHCM,44456
|
10
10
|
clarifai/client/lister.py,sha256=03KGMvs5RVyYqxLsSrWhNc34I8kiF1Ph0NeyEwu7nMU,2082
|
11
|
-
clarifai/client/model.py,sha256=
|
11
|
+
clarifai/client/model.py,sha256=TsIiId2a1eqR8Ct83f8KbqBsxiDT9XNPxqLSQtr3i1A,72930
|
12
12
|
clarifai/client/module.py,sha256=360JaOasX0DZCNE_Trj0LNTr-T_tUDZLfGpz0CdIi78,4248
|
13
|
-
clarifai/client/search.py,sha256=
|
14
|
-
clarifai/client/user.py,sha256=
|
13
|
+
clarifai/client/search.py,sha256=GaPWN6JmTQGZaCHr6U1yv0zqR6wKFl7i9IVLg2ul1CI,14254
|
14
|
+
clarifai/client/user.py,sha256=Fr3vDEHieqD7HRRKnlp9h-AIX4AuYBirRYtG4KLwSe8,11836
|
15
15
|
clarifai/client/workflow.py,sha256=e3axkhU6c6WcxK9P5tgmnV464k-afslSzsSXx6nSMgA,10560
|
16
16
|
clarifai/client/auth/__init__.py,sha256=7EwR0NrozkAUwpUnCsqXvE_p0wqx_SelXlSpKShKJK0,136
|
17
17
|
clarifai/client/auth/helper.py,sha256=hqwI7Zlsvivc-O9aAdtxyJT3zkpuMvbxjRaiCTsWYGk,14183
|
@@ -25,7 +25,7 @@ clarifai/constants/search.py,sha256=yYEqTaFg-KdnpJE_Ytp-EPVHIIC395iNtZrpVlLIf4o,
|
|
25
25
|
clarifai/constants/workflow.py,sha256=cECq1xdvf44MCdtK2AbkiuuwhyL-6OWZdQfYbsLKy_o,33
|
26
26
|
clarifai/datasets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
27
27
|
clarifai/datasets/export/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
28
|
-
clarifai/datasets/export/inputs_annotations.py,sha256=
|
28
|
+
clarifai/datasets/export/inputs_annotations.py,sha256=X1Y1XjnJrPrlwqv2aM4a1mBPUpWgEpz5stq2Vq-mLaM,9740
|
29
29
|
clarifai/datasets/upload/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
30
30
|
clarifai/datasets/upload/base.py,sha256=IP4sdBRfThk2l0W1rDWciFrAJnKwVsM-gu4zEslJ2_E,2198
|
31
31
|
clarifai/datasets/upload/features.py,sha256=oq0PGpAw8LEafiSkdMMl0yn-NJeZ7K_CKzpJ71b0H40,1731
|
@@ -96,8 +96,8 @@ clarifai/schema/search.py,sha256=JjTi8ammJgZZ2OGl4K6tIA4zEJ1Fr2ASZARXavI1j5c,244
|
|
96
96
|
clarifai/urls/helper.py,sha256=tjoMGGHuWX68DUB0pk4MEjrmFsClUAQj2jmVEM_Sy78,4751
|
97
97
|
clarifai/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
98
98
|
clarifai/utils/constants.py,sha256=MG_iHnSwNEyUZOpvsrTicNwaT4CIjmlK_Ixk_qqEX8g,142
|
99
|
-
clarifai/utils/logging.py,sha256=
|
100
|
-
clarifai/utils/misc.py,sha256=
|
99
|
+
clarifai/utils/logging.py,sha256=ubo_knWpCmlXmt6uKAYppIQef1IcwPUJdqeqwjxe3RI,4977
|
100
|
+
clarifai/utils/misc.py,sha256=WV3KGM5_MwHySVthjUK4O93x6F_kE1h3-xT4zE4EvnU,2150
|
101
101
|
clarifai/utils/model_train.py,sha256=Mndqy5GNu7kjQHjDyNVyamL0hQFLGSHcWhOuPyOvr1w,8005
|
102
102
|
clarifai/utils/evaluation/__init__.py,sha256=PYkurUrXrGevByj7RFb6CoU1iC7fllyQSfnnlo9WnY8,69
|
103
103
|
clarifai/utils/evaluation/helpers.py,sha256=d_dcASRI_lhsHIRukAF1S-w7XazLpK9y6E_ug3l50t4,18440
|
@@ -107,9 +107,9 @@ clarifai/workflows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
|
|
107
107
|
clarifai/workflows/export.py,sha256=vICRhIreqDSShxLKjHNM2JwzKsf1B4fdXB0ciMcA70k,1945
|
108
108
|
clarifai/workflows/utils.py,sha256=nGeB_yjVgUO9kOeKTg4OBBaBz-AwXI3m-huSVj-9W18,1924
|
109
109
|
clarifai/workflows/validate.py,sha256=yJq03MaJqi5AK3alKGJJBR89xmmjAQ31sVufJUiOqY8,2556
|
110
|
-
clarifai-10.
|
111
|
-
clarifai-10.
|
112
|
-
clarifai-10.
|
113
|
-
clarifai-10.
|
114
|
-
clarifai-10.
|
115
|
-
clarifai-10.
|
110
|
+
clarifai-10.8.0.dist-info/LICENSE,sha256=mUqF_d12-qE2n41g7C5_sq-BMLOcj6CNN-jevr15YHU,555
|
111
|
+
clarifai-10.8.0.dist-info/METADATA,sha256=4oERpF1zh5aLZU6ZUh4jh6XqXyl-4n9pnle4KlbwBOM,19372
|
112
|
+
clarifai-10.8.0.dist-info/WHEEL,sha256=uCRv0ZEik_232NlR4YDw4Pv3Ajt5bKvMH13NUU7hFuI,91
|
113
|
+
clarifai-10.8.0.dist-info/entry_points.txt,sha256=qZOr_MIPG0dBBE1zringDJS_wXNGTAA_SQ-zcbmDHOw,82
|
114
|
+
clarifai-10.8.0.dist-info/top_level.txt,sha256=wUMdCQGjkxaynZ6nZ9FAnvBUCgp5RJUVFSy2j-KYo0s,9
|
115
|
+
clarifai-10.8.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|