diff --git a/.gitignore b/.gitignore index b6e47617..843c6556 100644 --- a/.gitignore +++ b/.gitignore @@ -127,3 +127,6 @@ dmypy.json # Pyre type checker .pyre/ + +# Vscode +.vscode diff --git a/aixplain/enums/data_type.py b/aixplain/enums/data_type.py index fa79d070..11432bcf 100644 --- a/aixplain/enums/data_type.py +++ b/aixplain/enums/data_type.py @@ -24,7 +24,7 @@ from enum import Enum -class DataType(Enum): +class DataType(str, Enum): AUDIO = "audio" FLOAT = "float" IMAGE = "image" @@ -33,6 +33,8 @@ class DataType(Enum): TENSOR = "tensor" TEXT = "text" VIDEO = "video" + EMBEDDING = "embedding" + NUMBER = "number" def __str__(self): return self._value_ diff --git a/aixplain/enums/function.py b/aixplain/enums/function.py index bfab8427..9a6f47d4 100644 --- a/aixplain/enums/function.py +++ b/aixplain/enums/function.py @@ -55,6 +55,7 @@ def load_functions(): if input_data_object["required"] is True }, "output": {output_data_object["dataType"] for output_data_object in function["output"]}, + "spec": function } for function in resp["items"] } diff --git a/aixplain/factories/agent_factory/__init__.py b/aixplain/factories/agent_factory/__init__.py index 36380a76..6076eef6 100644 --- a/aixplain/factories/agent_factory/__init__.py +++ b/aixplain/factories/agent_factory/__init__.py @@ -24,10 +24,13 @@ import json import logging +from aixplain.enums.function import Function from aixplain.enums.supplier import Supplier from aixplain.modules.agent import Agent, Tool from aixplain.modules.agent.tool.model_tool import ModelTool from aixplain.modules.agent.tool.pipeline_tool import PipelineTool +from aixplain.modules.model import Model +from aixplain.modules.pipeline import Pipeline from aixplain.utils import config from typing import Dict, List, Optional, Text, Union @@ -64,11 +67,12 @@ def create( if isinstance(tool, ModelTool): tool_payload.append( { - "function": tool.function.value, + "function": tool.function.value if tool.function is not None else None, "type": "model", "description": tool.description, "supplier": tool.supplier.value["code"] if tool.supplier else None, "version": tool.version if tool.version else None, + "assetId": tool.model, } ) elif isinstance(tool, PipelineTool): @@ -113,6 +117,32 @@ def create( raise Exception(e) return agent + @classmethod + def create_model_tool( + cls, + model: Optional[Union[Model, Text]] = None, + function: Optional[Union[Function, Text]] = None, + supplier: Optional[Union[Supplier, Text]] = None, + ) -> ModelTool: + """Create a new model tool.""" + if function is not None and isinstance(function, str): + function = Function(function) + + if supplier is not None: + if isinstance(supplier, str): + for supplier_ in Supplier: + if supplier.lower() in [supplier.value["code"].lower(), supplier.value["name"].lower()]: + supplier = supplier_ + break + if isinstance(supplier, str): + supplier = None + return ModelTool(function=function, supplier=supplier, model=model) + + @classmethod + def create_pipeline_tool(cls, description: Text, pipeline: Union[Pipeline, Text]) -> PipelineTool: + """Create a new pipeline tool.""" + return PipelineTool(description=description, pipeline=pipeline) + @classmethod def list(cls) -> Dict: """List all agents available in the platform.""" diff --git a/aixplain/factories/agent_factory/utils.py b/aixplain/factories/agent_factory/utils.py index 6363a08e..4b314ef7 100644 --- a/aixplain/factories/agent_factory/utils.py +++ b/aixplain/factories/agent_factory/utils.py @@ -22,9 +22,10 @@ def build_agent(payload: Dict, api_key: Text = config.TEAM_API_KEY) -> Agent: break tool = ModelTool( - function=Function(tool["function"]), + function=Function(tool["function"]) if tool["function"] is not None else None, supplier=tool["supplier"], version=tool["version"], + model=tool["assetId"], ) elif tool["type"] == "pipeline": tool = PipelineTool(description=tool["description"], pipeline=tool["assetId"]) diff --git a/aixplain/factories/file_factory.py b/aixplain/factories/file_factory.py index e7d7c4da..adbebcd3 100644 --- a/aixplain/factories/file_factory.py +++ b/aixplain/factories/file_factory.py @@ -104,7 +104,7 @@ def check_storage_type(cls, input_link: Any) -> StorageType: return StorageType.TEXT @classmethod - def to_link(cls, data: Union[Text, Dict]) -> Union[Text, Dict]: + def to_link(cls, data: Union[Text, Dict], **kwargs) -> Union[Text, Dict]: """If user input data is a local file, upload to aiXplain platform Args: @@ -117,10 +117,10 @@ def to_link(cls, data: Union[Text, Dict]) -> Union[Text, Dict]: for key in data: if isinstance(data[key], str): if cls.check_storage_type(data[key]) == StorageType.FILE: - data[key] = cls.upload(local_path=data[key]) + data[key] = cls.upload(local_path=data[key], **kwargs) elif isinstance(data, str): if cls.check_storage_type(data) == StorageType.FILE: - data = cls.upload(local_path=data) + data = cls.upload(local_path=data, **kwargs) return data @classmethod diff --git a/aixplain/factories/model_factory.py b/aixplain/factories/model_factory.py index 0fb845f1..c11d837a 100644 --- a/aixplain/factories/model_factory.py +++ b/aixplain/factories/model_factory.py @@ -361,7 +361,7 @@ def create_asset_repo( if function_dict["name"] == function: function_id = function_dict["id"] if function_id is None: - raise Exception("Invalid function name") + raise Exception(f"Invalid function name {function}") create_url = urljoin(config.BACKEND_URL, f"sdk/models/onboard") logging.debug(f"URL: {create_url}") if api_key: diff --git a/aixplain/factories/pipeline_factory.py b/aixplain/factories/pipeline_factory/__init__.py similarity index 77% rename from aixplain/factories/pipeline_factory.py rename to aixplain/factories/pipeline_factory/__init__.py index 61bcb214..051c63fb 100644 --- a/aixplain/factories/pipeline_factory.py +++ b/aixplain/factories/pipeline_factory/__init__.py @@ -21,9 +21,10 @@ Pipeline Factory Class """ import json -import logging import os +import logging from typing import Dict, List, Optional, Text, Union +from aixplain.factories.pipeline_factory.utils import build_from_response from aixplain.enums.data_type import DataType from aixplain.enums.function import Function from aixplain.enums.supplier import Supplier @@ -45,27 +46,6 @@ class PipelineFactory: aixplain_key = config.AIXPLAIN_API_KEY backend_url = config.BACKEND_URL - @classmethod - def __get_typed_nodes(cls, response: Dict, type: str) -> List[Dict]: - # read "nodes" field from response and return the nodes that are marked by "type": type - return [node for node in response["nodes"] if node["type"].lower() == type.lower()] - - @classmethod - def __from_response(cls, response: Dict) -> Pipeline: - """Converts response Json to 'Pipeline' object - - Args: - response (Dict): Json from API - - Returns: - Pipeline: Coverted 'Pipeline' object - """ - if "api_key" not in response: - response["api_key"] = config.TEAM_API_KEY - input = cls.__get_typed_nodes(response, "input") - output = cls.__get_typed_nodes(response, "output") - return Pipeline(response["id"], response["name"], response["api_key"], input=input, output=output) - @classmethod def get(cls, pipeline_id: Text, api_key: Optional[Text] = None) -> Pipeline: """Create a 'Pipeline' object from pipeline id @@ -81,11 +61,20 @@ def get(cls, pipeline_id: Text, api_key: Optional[Text] = None) -> Pipeline: try: url = urljoin(cls.backend_url, f"sdk/pipelines/{pipeline_id}") if api_key is not None: - headers = {"Authorization": f"Token {api_key}", "Content-Type": "application/json"} + headers = { + "Authorization": f"Token {api_key}", + "Content-Type": "application/json", + } elif cls.aixplain_key != "": - headers = {"x-aixplain-key": f"{cls.aixplain_key}", "Content-Type": "application/json"} + headers = { + "x-aixplain-key": f"{cls.aixplain_key}", + "Content-Type": "application/json", + } else: - headers = {"Authorization": f"Token {config.TEAM_API_KEY}", "Content-Type": "application/json"} + headers = { + "Authorization": f"Token {config.TEAM_API_KEY}", + "Content-Type": "application/json", + } logging.info(f"Start service for GET Pipeline - {url} - {headers}") r = _request_with_retry("get", url, headers=headers) resp = r.json() @@ -93,16 +82,17 @@ def get(cls, pipeline_id: Text, api_key: Optional[Text] = None) -> Pipeline: resp["api_key"] = config.TEAM_API_KEY if api_key is not None: resp["api_key"] = api_key - pipeline = cls.__from_response(resp) + pipeline = build_from_response(resp, load_architecture=True) return pipeline - except Exception: + except Exception as e: + logging.exception(e) status_code = 400 if resp is not None and "statusCode" in resp: status_code = resp["statusCode"] message = resp["message"] message = f"Pipeline Creation: Status {status_code} - {message}" else: - message = "Pipeline Creation: Unspecified Error" + message = f"Pipeline Creation: Unspecified Error {e}" logging.error(message) raise Exception(f"Status {status_code}: {message}") @@ -127,14 +117,20 @@ def get_assets_from_page(cls, page_number: int) -> List[Pipeline]: try: url = urljoin(cls.backend_url, f"sdk/pipelines/?pageNumber={page_number}") if cls.aixplain_key != "": - headers = {"x-aixplain-key": f"{cls.aixplain_key}", "Content-Type": "application/json"} + headers = { + "x-aixplain-key": f"{cls.aixplain_key}", + "Content-Type": "application/json", + } else: - headers = {"Authorization": f"Token {config.TEAM_API_KEY}", "Content-Type": "application/json"} + headers = { + "Authorization": f"Token {config.TEAM_API_KEY}", + "Content-Type": "application/json", + } r = _request_with_retry("get", url, headers=headers) resp = r.json() logging.info(f"Listing Pipelines: Status of getting Pipelines on Page {page_number}: {resp}") all_pipelines = resp["items"] - pipeline_list = [cls.__from_response(pipeline_info_json) for pipeline_info_json in all_pipelines] + pipeline_list = [build_from_response(pipeline_info_json) for pipeline_info_json in all_pipelines] return pipeline_list except Exception as e: error_message = f"Listing Pipelines: Error in getting Pipelines on Page {page_number}: {e}" @@ -177,9 +173,15 @@ def list( url = urljoin(cls.backend_url, "sdk/pipelines/paginate") if cls.aixplain_key != "": - headers = {"x-aixplain-key": f"{cls.aixplain_key}", "Content-Type": "application/json"} + headers = { + "x-aixplain-key": f"{cls.aixplain_key}", + "Content-Type": "application/json", + } else: - headers = {"Authorization": f"Token {config.TEAM_API_KEY}", "Content-Type": "application/json"} + headers = { + "Authorization": f"Token {config.TEAM_API_KEY}", + "Content-Type": "application/json", + } assert 0 < page_size <= 100, "Pipeline List Error: Page size must be greater than 0 and not exceed 100." payload = { @@ -228,11 +230,43 @@ def list( total = resp["total"] logging.info(f"Response for POST List Pipeline - Page Total: {page_total} / Total: {total}") for pipeline in results: - pipelines.append(cls.__from_response(pipeline)) - return {"results": pipelines, "page_total": page_total, "page_number": page_number, "total": total} + pipelines.append(build_from_response(pipeline)) + return { + "results": pipelines, + "page_total": page_total, + "page_number": page_number, + "total": total, + } @classmethod - def create(cls, name: Text, pipeline: Union[Text, Dict], api_key: Optional[Text] = None) -> Pipeline: + def init(cls, name: Text, api_key: Optional[Text] = None) -> Pipeline: + """Initialize a new Pipeline + + Args: + name (Text): Pipeline Name + api_key (Optional[Text], optional): Team API Key to create the Pipeline. Defaults to None. + + Returns: + Pipeline: instance of the new pipeline + """ + if api_key is None: + api_key = config.TEAM_API_KEY + return Pipeline( + id="", + name=name, + api_key=api_key, + nodes=[], + links=[], + instance=None, + ) + + @classmethod + def create( + cls, + name: Text, + pipeline: Union[Text, Dict], + api_key: Optional[Text] = None, + ) -> Pipeline: """Draft Pipeline Creation Args: @@ -259,10 +293,17 @@ def create(cls, name: Text, pipeline: Union[Text, Dict], api_key: Optional[Text] if "functionType" in node and node["functionType"] == "AI": pipeline["nodes"][i]["functionType"] = pipeline["nodes"][i]["functionType"].lower() # prepare payload - payload = {"name": name, "status": "draft", "architecture": pipeline} + payload = { + "name": name, + "status": "draft", + "architecture": pipeline, + } url = urljoin(cls.backend_url, "sdk/pipelines") api_key = api_key if api_key is not None else config.TEAM_API_KEY - headers = {"Authorization": f"Token {api_key}", "Content-Type": "application/json"} + headers = { + "Authorization": f"Token {api_key}", + "Content-Type": "application/json", + } logging.info(f"Start service for POST Create Pipeline - {url} - {headers} - {json.dumps(payload)}") r = _request_with_retry("post", url, headers=headers, json=payload) response = r.json() diff --git a/aixplain/factories/pipeline_factory/utils.py b/aixplain/factories/pipeline_factory/utils.py new file mode 100644 index 00000000..465e5e7f --- /dev/null +++ b/aixplain/factories/pipeline_factory/utils.py @@ -0,0 +1,100 @@ +__author__ = "aixplain" +import logging + +from aixplain.enums import DataType +import aixplain.utils.config as config +from aixplain.modules.pipeline import Pipeline +from aixplain.modules.pipeline.designer import ( + Input, + Output, + AssetNode, + Decision, + Router, + Route, + Script, + Link, +) +from typing import Dict + + +def build_from_response(response: Dict, load_architecture: bool = False) -> Pipeline: + """Converts response Json to 'Pipeline' object + + Args: + response (Dict): Json from API + load_architecture (bool, optional): If True, the architecture will be loaded. Defaults to False. + + Returns: + Pipeline: Coverted 'Pipeline' object + """ + if "api_key" not in response: + response["api_key"] = config.TEAM_API_KEY + + # instantiating pipeline generic info + pipeline = Pipeline(response["id"], response["name"], response["api_key"]) + if load_architecture is True: + try: + # instantiating nodes + for node_json in response["nodes"]: + print(node_json) + if node_json["type"].lower() == "input": + node = Input( + data=node_json["data"] if "data" in node_json else None, + data_types=[DataType(dt) for dt in node_json["dataType"]], + ) + elif node_json["type"].lower() == "asset": + node = AssetNode(asset_id=node_json["assetId"]) + elif node_json["type"].lower() == "segmentor": + raise NotImplementedError() + elif node_json["type"].lower() == "reconstructor": + raise NotImplementedError() + elif node_json["type"].lower() == "decision": + node = Decision(routes=[Route(**route) for route in node_json["routes"]]) + elif node_json["type"].lower() == "router": + node = Router(routes=[Route(**route) for route in node_json["routes"]]) + elif node_json["type"].lower() == "script": + node = Script(fileId=node_json["fileId"]) + elif node_json["type"].lower() == "output": + node = Output() + + if "inputValues" in node_json: + [ + node.inputs.create_param( + data_type=DataType(input_param["dataType"]) if "dataType" in input_param else None, + code=input_param["code"], + value=input_param["value"] if "value" in input_param else None, + is_required=input_param["isRequired"] if "isRequired" in input_param else False, + ) + for input_param in node_json["inputValues"] + if input_param["code"] not in node.inputs + ] + if "outputValues" in node_json: + [ + node.outputs.create_param( + data_type=DataType(output_param["dataType"]) if "dataType" in output_param else None, + code=output_param["code"], + value=output_param["value"] if "value" in output_param else None, + is_required=output_param["isRequired"] if "isRequired" in output_param else False, + ) + for output_param in node_json["outputValues"] + if output_param["code"] not in node.outputs + ] + node.number = node_json["number"] + node.label = node_json["label"] + pipeline.add_node(node) + + # instantiating links + for link_json in response["links"]: + for param_mapping in link_json["paramMapping"]: + link = Link( + from_node=pipeline.get_node(link_json["from"]), + to_node=pipeline.get_node(link_json["to"]), + from_param=param_mapping["from"], + to_param=param_mapping["to"], + ) + pipeline.add_link(link) + except Exception as e: + logging.warning("Error loading pipeline architecture:, error: %s", e) + pipeline.nodes = [] + pipeline.links = [] + return pipeline diff --git a/aixplain/factories/script_factory.py b/aixplain/factories/script_factory.py new file mode 100644 index 00000000..35789561 --- /dev/null +++ b/aixplain/factories/script_factory.py @@ -0,0 +1,31 @@ +import os +import json +from typing import Tuple + +import requests + +from aixplain.utils import config + + +class ScriptFactory: + + @classmethod + def upload_script(cls, script_path: str) -> Tuple[str, str]: + try: + url = f"{config.BACKEND_URL}/sdk/pipelines/script" + headers = {"Authorization": f"Token {config.TEAM_API_KEY}"} + r = requests.post( + url, headers=headers, files={"file": open(script_path, "rb")} + ) + if 200 <= r.status_code < 300: + response = r.json() + else: + raise Exception() + except Exception: + response = {"fileId": ""} + + # get metadata info + fname = os.path.splitext(os.path.basename(script_path))[0] + file_size_kb = int(os.path.getsize(script_path) / 1024) + metadata = json.dumps({"name": fname, "size": file_size_kb}) + return response["fileId"], metadata diff --git a/aixplain/modules/agent/__init__.py b/aixplain/modules/agent/__init__.py index 2f244d56..c0604f6a 100644 --- a/aixplain/modules/agent/__init__.py +++ b/aixplain/modules/agent/__init__.py @@ -28,6 +28,7 @@ from aixplain.utils.file_utils import _request_with_retry from aixplain.enums.supplier import Supplier from aixplain.enums.asset_status import AssetStatus +from aixplain.enums.storage_type import StorageType from aixplain.modules.model import Model from aixplain.modules.agent.tool import Tool from aixplain.modules.agent.tool.model_tool import ModelTool @@ -96,31 +97,43 @@ def __init__( def run( self, - query: Text, + data: Optional[Union[Dict, Text]] = None, + query: Optional[Text] = None, session_id: Optional[Text] = None, history: Optional[List[Dict]] = None, name: Text = "model_process", timeout: float = 300, parameters: Dict = {}, wait_time: float = 0.5, + content: Optional[Union[Dict[Text, Text], List[Text]]] = None, ) -> Dict: """Runs an agent call. Args: - query (Text): query to be processed by the agent. + data (Optional[Union[Dict, Text]], optional): data to be processed by the agent. Defaults to None. + query (Optional[Text], optional): query to be processed by the agent. Defaults to None. session_id (Optional[Text], optional): conversation Session ID. Defaults to None. history (Optional[List[Dict]], optional): chat history (in case session ID is None). Defaults to None. name (Text, optional): ID given to a call. Defaults to "model_process". timeout (float, optional): total polling time. Defaults to 300. parameters (Dict, optional): optional parameters to the model. Defaults to "{}". wait_time (float, optional): wait time in seconds between polling calls. Defaults to 0.5. + content (Union[Dict[Text, Text], List[Text]], optional): Content inputs to be processed according to the query. Defaults to None. Returns: Dict: parsed output from model """ start = time.time() try: - response = self.run_async(query=query, session_id=session_id, history=history, name=name, parameters=parameters) + response = self.run_async( + data=data, + query=query, + session_id=session_id, + history=history, + name=name, + parameters=parameters, + content=content, + ) if response["status"] == "FAILED": end = time.time() response["elapsed_time"] = end - start @@ -137,27 +150,61 @@ def run( def run_async( self, - query: Text, + data: Optional[Union[Dict, Text]] = None, + query: Optional[Text] = None, session_id: Optional[Text] = None, history: Optional[List[Dict]] = None, name: Text = "model_process", parameters: Dict = {}, + content: Optional[Union[Dict[Text, Text], List[Text]]] = None, ) -> Dict: """Runs asynchronously an agent call. Args: - query (Text): query to be processed by the agent. + data (Optional[Union[Dict, Text]], optional): data to be processed by the agent. Defaults to None. + query (Optional[Text], optional): query to be processed by the agent. Defaults to None. session_id (Optional[Text], optional): conversation Session ID. Defaults to None. history (Optional[List[Dict]], optional): chat history (in case session ID is None). Defaults to None. name (Text, optional): ID given to a call. Defaults to "model_process". parameters (Dict, optional): optional parameters to the model. Defaults to "{}". + content (Union[Dict[Text, Text], List[Text]], optional): Content inputs to be processed according to the query. Defaults to None. Returns: dict: polling URL in response """ - headers = {"x-api-key": self.api_key, "Content-Type": "application/json"} from aixplain.factories.file_factory import FileFactory + assert data is not None or query is not None, "Either 'data' or 'query' must be provided." + if data is not None: + if isinstance(data, dict): + assert "query" in data and data["query"] is not None, "When providing a dictionary, 'query' must be provided." + query = data.get("query") + if session_id is None: + session_id = data.get("session_id") + if history is None: + history = data.get("history") + if content is None: + content = data.get("content") + else: + query = data + + # process content inputs + if content is not None: + assert FileFactory.check_storage_type(query) == StorageType.TEXT, "When providing 'content', query must be text." + + if isinstance(content, list): + assert len(content) <= 3, "The maximum number of content inputs is 3." + for input_link in content: + input_link = FileFactory.to_link(input_link) + query += f"\n{input_link}" + elif isinstance(content, dict): + for key, value in content.items(): + assert "{{" + key + "}}" in query, f"Key '{key}' not found in query." + value = FileFactory.to_link(value) + query = query.replace("{{" + key + "}}", f"'{value}'") + + headers = {"x-api-key": self.api_key, "Content-Type": "application/json"} + payload = {"id": self.id, "query": FileFactory.to_link(query), "sessionId": session_id, "history": history} payload.update(parameters) payload = json.dumps(payload) diff --git a/aixplain/modules/agent/tool/model_tool.py b/aixplain/modules/agent/tool/model_tool.py index 69bf28d5..e15a8bea 100644 --- a/aixplain/modules/agent/tool/model_tool.py +++ b/aixplain/modules/agent/tool/model_tool.py @@ -20,11 +20,12 @@ Description: Agentification Class """ -from typing import Optional +from typing import Optional, Union, Text from aixplain.enums.function import Function from aixplain.enums.supplier import Supplier from aixplain.modules.agent.tool import Tool +from aixplain.modules.model import Model class ModelTool(Tool): @@ -37,24 +38,41 @@ class ModelTool(Tool): def __init__( self, - function: Function, + function: Optional[Function] = None, supplier: Optional[Supplier] = None, + model: Optional[Union[Text, Model]] = None, **additional_info, ) -> None: """Specialized software or resource designed to assist the AI in executing specific tasks or functions based on user commands. Args: - function (Function): task that the tool performs - supplier (Optional[Union[Dict, Text, Supplier, int]], optional): Preferred supplier to perform the task. Defaults to None. + function (Optional[Function], optional): task that the tool performs. Defaults to None. + supplier (Optional[Supplier], optional): Preferred supplier to perform the task. Defaults to None.. Defaults to None. + model (Optional[Union[Text, Model]], optional): Model function. Defaults to None. """ + assert ( + function is not None or model is not None + ), "Agent Creation Error: Either function or model must be provided when instantiating a tool." super().__init__("", "", **additional_info) - if isinstance(function, str): - function = Function(function) - self.function = function + if function is not None: + if isinstance(function, str): + function = Function(function) try: if isinstance(supplier, dict): supplier = Supplier(supplier) except Exception: supplier = None + + if model is not None: + if isinstance(model, Text) is True: + from aixplain.factories.model_factory import ModelFactory + + model = ModelFactory.get(model) + function = model.function + if isinstance(model.supplier, Supplier): + supplier = model.supplier + model = model.id self.supplier = supplier + self.model = model + self.function = function diff --git a/aixplain/modules/model/llm_model.py b/aixplain/modules/model/llm_model.py index 14b9c7f4..5c5c4140 100644 --- a/aixplain/modules/model/llm_model.py +++ b/aixplain/modules/model/llm_model.py @@ -24,7 +24,6 @@ import json import logging import traceback -from aixplain.factories.file_factory import FileFactory from aixplain.enums import Function, Supplier from aixplain.modules.model import Model from aixplain.utils import config @@ -182,6 +181,8 @@ def run_async( """ headers = {"x-api-key": self.api_key, "Content-Type": "application/json"} + from aixplain.factories.file_factory import FileFactory + data = FileFactory.to_link(data) if isinstance(data, dict): payload = data diff --git a/aixplain/modules/pipeline/__init__.py b/aixplain/modules/pipeline/__init__.py new file mode 100644 index 00000000..d2381c3a --- /dev/null +++ b/aixplain/modules/pipeline/__init__.py @@ -0,0 +1,3 @@ +from .pipeline import Pipeline + +__all__ = ["Pipeline"] diff --git a/aixplain/modules/pipeline.py b/aixplain/modules/pipeline/asset.py similarity index 81% rename from aixplain/modules/pipeline.py rename to aixplain/modules/pipeline/asset.py index ed131018..ad7cfa1b 100644 --- a/aixplain/modules/pipeline.py +++ b/aixplain/modules/pipeline/asset.py @@ -66,13 +66,20 @@ def __init__( version (Text, optional): version of the pipeline. Defaults to "1.0". **additional_info: Any additional Pipeline info to be saved """ + if not name: + raise ValueError("Pipeline name is required") + super().__init__(id, name, "", supplier, version) self.api_key = api_key self.url = f"{url}/assets/pipeline/execution/run" self.additional_info = additional_info def __polling( - self, poll_url: Text, name: Text = "pipeline_process", wait_time: float = 1.0, timeout: float = 20000.0 + self, + poll_url: Text, + name: Text = "pipeline_process", + wait_time: float = 1.0, + timeout: float = 20000.0, ) -> Dict: """Keeps polling the platform to check whether an asynchronous call is done. @@ -125,7 +132,10 @@ def poll(self, poll_url: Text, name: Text = "pipeline_process") -> Dict: Dict: response obtained by polling call """ - headers = {"x-api-key": self.api_key, "Content-Type": "application/json"} + headers = { + "x-api-key": self.api_key, + "Content-Type": "application/json", + } r = _request_with_retry("get", poll_url, headers=headers) try: resp = r.json() @@ -172,9 +182,17 @@ def run( logging.error(error_message) logging.exception(error_message) end = time.time() - return {"status": "FAILED", "error": error_message, "elapsed_time": end - start} + return { + "status": "FAILED", + "error": error_message, + "elapsed_time": end - start, + } - def __prepare_payload(self, data: Union[Text, Dict], data_asset: Optional[Union[Text, Dict]] = None) -> Dict: + def __prepare_payload( + self, + data: Union[Text, Dict], + data_asset: Optional[Union[Text, Dict]] = None, + ) -> Dict: """Prepare pipeline execution payload, validating the input data Args: @@ -184,7 +202,11 @@ def __prepare_payload(self, data: Union[Text, Dict], data_asset: Optional[Union[ Returns: Dict: pipeline execution payload """ - from aixplain.factories import CorpusFactory, DatasetFactory, FileFactory + from aixplain.factories import ( + CorpusFactory, + DatasetFactory, + FileFactory, + ) # if an input data asset is provided, just handle the data if data_asset is None: @@ -287,7 +309,10 @@ def run_async( Returns: Dict: polling URL in response """ - headers = {"x-api-key": self.api_key, "Content-Type": "application/json"} + headers = { + "x-api-key": self.api_key, + "Content-Type": "application/json", + } payload = self.__prepare_payload(data=data, data_asset=data_asset) payload.update(kwargs) @@ -309,7 +334,12 @@ def run_async( response["error"] = resp return response - def update(self, pipeline: Union[Text, Dict], save_as_asset: bool = False, api_key: Optional[Text] = None): + def update( + self, + pipeline: Union[Text, Dict], + save_as_asset: bool = False, + api_key: Optional[Text] = None, + ): """Update Pipeline Args: @@ -336,10 +366,17 @@ def update(self, pipeline: Union[Text, Dict], save_as_asset: bool = False, api_k status = "draft" if save_as_asset is True: status = "onboarded" - payload = {"name": self.name, "status": status, "architecture": pipeline} + payload = { + "name": self.name, + "status": status, + "architecture": pipeline, + } url = urljoin(config.BACKEND_URL, f"sdk/pipelines/{self.id}") api_key = api_key if api_key is not None else config.TEAM_API_KEY - headers = {"Authorization": f"Token {api_key}", "Content-Type": "application/json"} + headers = { + "Authorization": f"Token {api_key}", + "Content-Type": "application/json", + } logging.info(f"Start service for PUT Update Pipeline - {url} - {headers} - {json.dumps(payload)}") r = _request_with_retry("put", url, headers=headers, json=payload) response = r.json() @@ -351,7 +388,10 @@ def delete(self) -> None: """Delete Dataset service""" try: url = urljoin(config.BACKEND_URL, f"sdk/pipelines/{self.id}") - headers = {"Authorization": f"Token {config.TEAM_API_KEY}", "Content-Type": "application/json"} + headers = { + "Authorization": f"Token {config.TEAM_API_KEY}", + "Content-Type": "application/json", + } logging.info(f"Start service for DELETE Pipeline - {url} - {headers}") r = _request_with_retry("delete", url, headers=headers) if r.status_code != 200: @@ -360,3 +400,48 @@ def delete(self) -> None: message = "Pipeline Deletion Error: Make sure the pipeline exists and you are the owner." logging.error(message) raise Exception(f"{message}") + + def save(self, save_as_asset: bool = False, api_key: Optional[Text] = None): + """Save Pipeline + + Args: + save_as_asset (bool, optional): Save as asset (True) or draft (False). Defaults to False. + api_key (Optional[Text], optional): Team API Key to create the Pipeline. Defaults to None. + + Raises: + Exception: Make sure the pipeline to be save is in a JSON file. + """ + try: + pipeline = self.to_dict() + + for i, node in enumerate(pipeline["nodes"]): + if "functionType" in node and node["functionType"] == "AI": + pipeline["nodes"][i]["functionType"] = pipeline["nodes"][i]["functionType"].lower() + # prepare payload + status = "draft" + if save_as_asset is True: + status = "onboarded" + payload = { + "name": self.name, + "status": status, + "architecture": pipeline, + } + + if self.id != "": + method = "put" + url = urljoin(config.BACKEND_URL, f"sdk/pipelines/{self.id}") + else: + method = "post" + url = urljoin(config.BACKEND_URL, "sdk/pipelines") + api_key = api_key if api_key is not None else config.TEAM_API_KEY + headers = { + "Authorization": f"Token {api_key}", + "Content-Type": "application/json", + } + logging.info(f"Start service for Save Pipeline - {url} - {headers} - {json.dumps(payload)}") + r = _request_with_retry(method, url, headers=headers, json=payload) + response = r.json() + self.id = response["id"] + logging.info(f"Pipeline {response['id']} Saved.") + except Exception as e: + raise Exception(e) diff --git a/aixplain/modules/pipeline/default.py b/aixplain/modules/pipeline/default.py new file mode 100644 index 00000000..b0499159 --- /dev/null +++ b/aixplain/modules/pipeline/default.py @@ -0,0 +1,17 @@ +from .asset import Pipeline as PipelineAsset +from .designer import DesignerPipeline + + +class DefaultPipeline(PipelineAsset, DesignerPipeline): + + def __init__(self, *args, **kwargs): + PipelineAsset.__init__(self, *args, **kwargs) + DesignerPipeline.__init__(self) + + def save(self, *args, **kwargs): + self.auto_infer() + self.validate() + super().save(*args, **kwargs) + + def to_dict(self) -> dict: + return self.serialize() diff --git a/aixplain/modules/pipeline/designer/README.md b/aixplain/modules/pipeline/designer/README.md new file mode 100644 index 00000000..a1806868 --- /dev/null +++ b/aixplain/modules/pipeline/designer/README.md @@ -0,0 +1,194 @@ +# Aixplan SDK User Guide + +## Introduction + +Aixplan SDK provides a programmatic API to create pipelines for building solutions on the Aixplain platform. + +## Minimal Example + +Here's a quick example to get you started: + +```python +from aixplain.factories.pipeline_factory import PipelineFactory + +TRANSLATION_ASSET_ID = 'your-translation-asset-id' + +pipeline = PipelineFactory.init('Translation Pipeline') +input_node = pipeline.input() +translation_node = pipeline.translation(assetId=TRANSLATION_ASSET_ID) + +input_node.link(translation_node, 'input', 'text') + +output_node = translation_node.use_output('data') + +pipeline.save() +outputs = pipeline.run('This is example text to translate') + +print(outputs) +``` + +## Instantiating Nodes + +To create a pipeline and instantiate nodes, use the following code: + +```python +from aixplain.factories.pipeline_factory import PipelineFactory +from aixplain.modules.pipeline.designer import Input + +pipeline = PipelineFactory.init("My Pipeline") +input_node = Input(*args, **kwargs) +input_node.attach(pipeline) +``` + +Alternatively, add nodes to the pipeline using `add_node`: + +```python +input_node = pipeline.add_node(Input(*args, **kwargs)) +``` + +You can also pass the pipeline to the node constructor: + +```python +input_node = Input(*args, pipeline=pipeline, **kwargs) +``` + +Or directly instantiate the node within the pipeline: + +```python +input_node = pipeline.input(*args, **kwargs) +``` + +## Adding Output Nodes + +Each pipeline should have at least one input, asset, and output node. Add output nodes like any other node: + +```python +translation_node = pipeline.translation(assetId=TRANSLATION_ASSET_ID) +output_node = pipeline.output(*args, **kwargs) +translation_node.link(output_node, 'data', 'output') +``` + +For nodes implementing the `Outputable` mixin, use the shortcut syntax: + +```python +output_node = translation_node.use_output('parameter_name_we_are_interested_in') +``` + +## Asset Nodes and Automatic Population + +Asset nodes are used to run models and should have an asset ID. Once instantiated, an asset node contains all model information and parameters which is populated automatically by interacting with the Aixplain platform. + +```python +translation_node = pipeline.translation(assetId=TRANSLATION_ASSET_ID) +print(translation_node.inputs) +print(translation_node.outputs) +``` + +## Handling Parameters + +Parameters are accessed via the `inputs` and `outputs` attributes of the node, behaving as proxy objects to the parameters. + +```python +print(translation_node.inputs.text) +print(translation_node.outputs.data) +``` + +Add parameters to a node using `create_param` on corresponding `inputs` or `outputs` attribute: + +```python +translation_node.inputs.create_param('source_language', DataType.TEXT) +translation_node.outputs.create_param('source_audio', DataType.AUDIO) +``` + +Alternatively, instantiate parameters directly using `InputParam` or `OutputParam` classes: + +```python +from aixplain.modules.pipeline.designer import InputParam, OutputParam + +source_language = InputParam( + code='source_language', + dataType=DataType.TEXT, + is_required=True, + node=translation_node +) +``` + +Or add parameters explicitly: + +```python +source_audio = OutputParam(dataType=DataType.AUDIO, code='source_audio') +translation_node.outputs.add_param(source_audio) +``` + +In case of need, any parameter value can be set directly without requiring node linking: + +```python +translation_node.inputs.text = 'This is example text to translate' +translation_node.inputs.source_language = 'en' +``` + +This will implicity set the `value` attribute of the parameter object. + +## Linking Nodes + +Link nodes to pass data between them using the `link` method. This method links the output of one node to the input of another on specified parameters. + +Consider the following nodes: + +```python +input_node = pipeline.input() +translation_node = pipeline.translation(assetId=TRANSLATION_ASSET_ID) +``` + +Link nodes together: + +```python +input_node.link(translation_node, 'input', 'text') +``` + +Specify parameters explicitly: + +```python +input_node.link(translation_node, from_param='input', to_param='text') +``` + +Or use parameter instances: + +```python +input_node.link(translation_node, from_param=input_node.outputs.input, to_param=translation_node.inputs.text) +``` + +You can also link parameters directly if you find it more convenient: + +```python +input_node.outputs.input.link(translation_node.inputs.text) +``` + +## Validating the Pipeline + +Use the `validate` method to ensure the pipeline is valid and ready to run. This method raises an exception if the pipeline has issues. + +```python +pipeline.validate() +``` + +This method will check the following: + * Contains at least one input, asset, and output node + * All input nodes are linked in, output nodes are linked out, and rest are linked in and out + * All links pointing to the correct nodes and corresponding params. + * All required params are either set or linked + * All linked params have the same data type + +Otherwise raises `ValueError` with a cause if the pipeline is not valid. + +## Save and Run the Pipeline + +Save the pipeline before running it. The `save` method implicitly calls the `validate` method. Use the `run` method to execute the pipeline with input data. + +```python +pipeline.save() # Raises an exception if there are semantic issues +outputs = pipeline.run('This is example text to translate') +print(outputs) +``` + +This guide covers the basic usage of the programmatic api of Aixplan SDK for creating and running pipelines. For more advanced features, refer to the code itself. \ No newline at end of file diff --git a/aixplain/modules/pipeline/designer/__init__.py b/aixplain/modules/pipeline/designer/__init__.py new file mode 100644 index 00000000..0bb56542 --- /dev/null +++ b/aixplain/modules/pipeline/designer/__init__.py @@ -0,0 +1,66 @@ +from .nodes import ( + AssetNode, + Decision, + Script, + Input, + Output, + Route, + Router, + BaseReconstructor, + BaseSegmentor, +) +from .pipeline import DesignerPipeline +from .base import ( + Node, + Link, + Param, + ParamProxy, + InputParam, + OutputParam, + Inputs, + Outputs, + TI, + TO, +) +from .enums import ( + ParamType, + RouteType, + Operation, + NodeType, + AssetType, + FunctionType, +) +from .mixins import LinkableMixin, OutputableMixin, RoutableMixin + + +__all__ = [ + "DesignerPipeline", + "AssetNode", + "Decision", + "Script", + "Input", + "Output", + "Route", + "Router", + "BaseReconstructor", + "BaseSegmentor", + "Node", + "Link", + "Param", + "ParamType", + "InputParam", + "OutputParam", + "RouteType", + "Operation", + "NodeType", + "AssetType", + "FunctionType", + "LinkableMixin", + "OutputableMixin", + "RoutableMixin", + "Inputs", + "Outputs", + "ParamProxy", + "TI", + "TO", +] diff --git a/aixplain/modules/pipeline/designer/base.py b/aixplain/modules/pipeline/designer/base.py new file mode 100644 index 00000000..8bea73d6 --- /dev/null +++ b/aixplain/modules/pipeline/designer/base.py @@ -0,0 +1,375 @@ +from typing import ( + List, + Union, + TYPE_CHECKING, + Generic, + TypeVar, + Type, + Optional, + Iterator, +) + +from aixplain.enums import DataType +from .enums import NodeType, ParamType + + +if TYPE_CHECKING: + from .pipeline import DesignerPipeline + +TI = TypeVar("TI", bound="Inputs") +TO = TypeVar("TO", bound="Outputs") + + +class Serializable: + def serialize(self) -> dict: + raise NotImplementedError() + + +class Param(Serializable): + """ + Param class, this class will be used to create the parameters of the node. + """ + + code: str + param_type: ParamType + data_type: Optional[DataType] = None + value: Optional[str] = None + node: Optional["Node"] = None + link_: Optional["Link"] = None + + def __init__( + self, + code: str, + data_type: Optional[DataType] = None, + value: Optional[str] = None, + node: Optional["Node"] = None, + param_type: Optional[ParamType] = None, + ): + self.code = code + self.data_type = data_type + self.value = value + + # is subclasses do not set the param type, set it to None + self.param_type = getattr(self, "param_type", param_type) + + if node: + self.attach_to(node) + + def attach_to(self, node: "Node") -> "Param": + """ + Attach the param to the node. + :param node: the node + :return: the param + """ + assert not self.node, "Param already attached to a node" + assert self.param_type, "Param type not set" + if self.param_type == ParamType.INPUT: + node.inputs.add_param(self) + elif self.param_type == ParamType.OUTPUT: + node.outputs.add_param(self) + else: + raise ValueError("Invalid param type") + self.node = node + return self + + def link(self, to_param: "Param") -> "Param": + """ + Link the output of the param to the input of another param. + :param to_param: the input param + :return: the param + """ + assert self.node, "Param not attached to a node" + assert to_param.param_type == ParamType.INPUT, "Invalid param type" + assert self in self.node.outputs, "Param not registered as output" + return to_param.back_link(self) + + def back_link(self, from_param: "Param") -> "Param": + """ + Link the input of the param to the output of another param. + :param from_param: the output param + :return: the param + """ + assert self.node, "Param not attached to a node" + assert from_param.param_type == ParamType.OUTPUT, "Invalid param type" + assert self.code in self.node.inputs, "Param not registered as input" + link = from_param.node.link(self.node, from_param, self) + self.link_ = link + from_param.link_ = link + return link + + def serialize(self) -> dict: + return { + "code": self.code, + "dataType": self.data_type, + "value": self.value, + } + + +class InputParam(Param): + + param_type: ParamType = ParamType.INPUT + is_required: bool = True + + def __init__(self, *args, is_required: bool = True, **kwargs): + super().__init__(*args, **kwargs) + self.is_required = is_required + + +class OutputParam(Param): + + param_type: ParamType = ParamType.OUTPUT + + +class Link(Serializable): + """ + Link class, this class will be used to link the output of the node to the + input of another node. + """ + + from_node: "Node" + to_node: "Node" + from_param: str + to_param: str + + pipeline: Optional["DesignerPipeline"] = None + + def __init__( + self, + from_node: "Node", + to_node: "Node", + from_param: Union[Param, str], + to_param: Union[Param, str], + pipeline: "DesignerPipeline" = None, + ): + + assert from_param in from_node.outputs, "Invalid from param" + assert to_param in to_node.inputs, "Invalid to param" + + if isinstance(from_param, Param): + from_param = from_param.code + if isinstance(to_param, Param): + to_param = to_param.code + + self.from_node = from_node + self.to_node = to_node + self.from_param = from_param + self.to_param = to_param + + if pipeline: + self.attach_to(pipeline) + + # self.validate() + self.auto_infer() + + def auto_infer(self): + from_param = self.from_node.outputs[self.from_param] + to_param = self.to_node.inputs[self.to_param] + + # if one of the data types is missing, infer the other one + data_type = from_param.data_type or to_param.data_type + from_param.data_type = data_type + to_param.data_type = data_type + + def infer_data_type(node): + from .nodes import Input, Output + + if isinstance(node, Input) or isinstance(node, Output): + if data_type and data_type not in node.data_types: + node.data_types.append(data_type) + + infer_data_type(self.from_node) + infer_data_type(self.to_node) + + def validate(self): + from_param = self.from_node.outputs[self.from_param] + to_param = self.to_node.inputs[self.to_param] + + # Should we check for data type mismatch? + if from_param.data_type and to_param.data_type: + if from_param.data_type != to_param.data_type: + raise ValueError( + f"Data type mismatch between {from_param.data_type} and {to_param.data_type}" + ) # noqa + + def attach_to(self, pipeline: "DesignerPipeline"): + """ + Attach the link to the pipeline. + :param pipeline: the pipeline + """ + assert not self.pipeline, "Link already attached to a pipeline" + if not self.from_node.pipeline or self.from_node not in pipeline.nodes: + self.from_node.attach_to(pipeline) + if not self.to_node.pipeline or self.to_node not in pipeline.nodes: + self.to_node.attach_to(pipeline) + + self.pipeline = pipeline + self.pipeline.links.append(self) + return self + + def serialize(self) -> dict: + assert self.from_node.number is not None, "From node number not set" + assert self.to_node.number is not None, "To node number not set" + return { + "from": self.from_node.number, + "to": self.to_node.number, + "paramMapping": [ + { + "from": self.from_param, + "to": self.to_param, + } + ], + } + + +class ParamProxy(Serializable): + + node: "Node" + + def __init__(self, node: "Node", *args, **kwargs): + super().__init__(*args, **kwargs) + self.node = node + self._params = [] + + def add_param(self, param: Param) -> None: + # check if param already registered + if param in self: + raise ValueError( + f"Parameter with code '{param.code}' already exists." + ) + self._params.append(param) + # also set attribute on the node dynamically if there's no + # any attribute with the same name + if not hasattr(self, param.code): + setattr(self, param.code, param) + + def _create_param( + self, code: str, data_type: DataType = None, value: any = None + ) -> Param: + raise NotImplementedError() + + def create_param( + self, + code: str, + data_type: DataType = None, + value: any = None, + is_required: bool = False, + ) -> Param: + param = self._create_param(code, data_type, value) + param.is_required = is_required + self.add_param(param) + param.node = self.node + return param + + def __getitem__(self, code: str) -> Param: + for param in self._params: + if param.code == code: + return param + raise KeyError(f"Parameter with code '{code}' not found.") + + def __setitem__(self, code: str, value: str) -> None: + # set param value on set item to avoid setting it manually + self[code].value = value + + def __setattr__(self, name: str, value: any) -> None: + # set param value on attribute assignment to avoid setting it manually + if isinstance(value, str) and hasattr(self, name): + self[name].value = value + else: + super().__setattr__(name, value) + + def __contains__(self, param: Union[str, Param]) -> bool: + code = param if isinstance(param, str) else param.code + return any(param.code == code for param in self._params) + + def __iter__(self) -> Iterator[Param]: + return iter(self._params) + + def __len__(self) -> int: + return len(self._params) + + def serialize(self) -> List[dict]: + return [param.serialize() for param in self._params] + + +class Inputs(ParamProxy): + def _create_param( + self, + code: str, + data_type: DataType = None, + value: any = None, + is_required: bool = False, + ) -> InputParam: + return InputParam( + code=code, + data_type=data_type, + value=value, + is_required=is_required, + ) + + +class Outputs(ParamProxy): + def _create_param( + self, code: str, data_type: DataType = None, value: any = None + ) -> OutputParam: + return OutputParam(code=code, data_type=data_type, value=value) + + +class Node(Generic[TI, TO], Serializable): + """ + Node class is the base class for all the nodes in the pipeline. This class + will be used to create the nodes and link them together. + """ + + number: Optional[int] = None + label: Optional[str] = None + type: Optional[NodeType] = None + + inputs: Optional[TI] = None + outputs: Optional[TO] = None + inputs_class: Optional[Type[TI]] = Inputs + outputs_class: Optional[Type[TO]] = Outputs + pipeline: Optional["DesignerPipeline"] = None + + def __init__( + self, + pipeline: "DesignerPipeline" = None, + number: Optional[int] = None, + label: Optional[str] = None, + ): + self.inputs = self.inputs_class(node=self) + self.outputs = self.outputs_class(node=self) + self.number = number + self.label = label + + if pipeline: + self.attach_to(pipeline) + + def attach_to(self, pipeline: "DesignerPipeline"): + """ + Attach the node to the pipeline. + :param pipeline: the pipeline + """ + assert not self.pipeline, "Node already attached to a pipeline" + assert ( + self not in pipeline.nodes + ), "Node already attached to a pipeline" + assert self.type, "Node type not set" + + self.pipeline = pipeline + if self.number is None: + self.number = len(pipeline.nodes) + if self.label is None: + self.label = f"{self.type.value}(ID={self.number})" + + assert not pipeline.get_node(self.number), "Node number already exists" + pipeline.nodes.append(self) + return self + + def serialize(self) -> dict: + return { + "number": self.number, + "label": self.label, + "type": self.type.value, + "inputValues": self.inputs.serialize(), + "outputValues": self.outputs.serialize(), + } diff --git a/aixplain/modules/pipeline/designer/enums.py b/aixplain/modules/pipeline/designer/enums.py new file mode 100644 index 00000000..4c044dba --- /dev/null +++ b/aixplain/modules/pipeline/designer/enums.py @@ -0,0 +1,43 @@ +from enum import Enum + + +class RouteType(str, Enum): + CHECK_TYPE = "checkType" + CHECK_VALUE = "checkValue" + + +class Operation(str, Enum): + GREATER_THAN = "greaterThan" + GREATER_THAN_OR_EQUAL = "greaterThanOrEqual" + LESS_THAN = "lessThan" + LESS_THAN_OR_EQUAL = "lessThanOrEqual" + EQUAL = "equal" + DIFFERENT = "different" + CONTAIN = "contain" + NOT_CONTAIN = "notContain" + + +class NodeType(str, Enum): + ASSET = "ASSET" + INPUT = "INPUT" + OUTPUT = "OUTPUT" + SCRIPT = "SCRIPT" + SEGMENTOR = "SEGMENT" + RECONSTRUCTOR = "RECONSTRUCT" + ROUTER = "ROUTER" + DECISION = "DECISION" + + +class AssetType(str, Enum): + MODEL = "MODEL" + + +class FunctionType(str, Enum): + AI = "AI" + SEGMENTOR = "SEGMENTOR" + RECONSTRUCTOR = "RECONSTRUCTOR" + + +class ParamType: + INPUT = "INPUT" + OUTPUT = "OUTPUT" diff --git a/aixplain/modules/pipeline/designer/mixins.py b/aixplain/modules/pipeline/designer/mixins.py new file mode 100644 index 00000000..e5aad3c4 --- /dev/null +++ b/aixplain/modules/pipeline/designer/mixins.py @@ -0,0 +1,85 @@ +from typing import Union +from .base import Node, Link, Param + + +class LinkableMixin: + """ + Linkable mixin class, this class will be used to link the output of the + node to the input of another node. + + This class will be used to link the output of the node to the input of + another node. + """ + + def link( + self, + to_node: Node, + from_param: Union[str, Param], + to_param: Union[str, Param], + ) -> Link: + """ + Link the output of the node to the input of another node. This method + will link the output of the node to the input of another node. + + :param to_node: the node to link to the output + :param from_param: the output parameter or the code of the output + parameter + :param to_param: the input parameter or the code of the input parameter + :return: the link + """ + return Link( + pipeline=self.pipeline, + from_node=self, + to_node=to_node, + from_param=from_param, + to_param=to_param, + ) + + +class RoutableMixin: + """ + Routable mixin class, this class will be used to route the input data to + different nodes based on the input data type. + """ + + def route(self, *params: Param) -> Node: + """ + Route the input data to different nodes based on the input data type. + This method will automatically link the input data to the output data + of the node. + + :param params: the output parameters + :return: the router node + """ + assert self.pipeline, "Node not attached to a pipeline" + + router = self.pipeline.router( + [(param.data_type, param.node) for param in params] + ) + self.outputs.input.link(router.inputs.input) + for param in params: + router.outputs.input.link(param) + return router + + +class OutputableMixin: + """ + Outputable mixin class, this class will be used to link the output of the + node to the output node of the pipeline. + """ + + def use_output(self, param: Union[str, Param]) -> Node: + """ + Use the output of the node as the output of the pipeline. + This method will automatically link the output of the node to the + output node of the pipeline. + + :param param: the output parameter or the code of the output parameter + :return: the output node + """ + assert self.pipeline, "Node not attached to a pipeline" + output = self.pipeline.output() + if isinstance(param, str): + param = self.outputs[param] + param.link(output.inputs.output) + return output diff --git a/aixplain/modules/pipeline/designer/nodes.py b/aixplain/modules/pipeline/designer/nodes.py new file mode 100644 index 00000000..22152239 --- /dev/null +++ b/aixplain/modules/pipeline/designer/nodes.py @@ -0,0 +1,464 @@ +from typing import List, Union, Type, TYPE_CHECKING, Optional + +from aixplain.modules import Model +from aixplain.enums import DataType + +from .enums import ( + NodeType, + FunctionType, + RouteType, + Operation, + AssetType, +) +from .base import ( + Node, + Link, + Param, + InputParam, + OutputParam, + TI, + TO, + Inputs, + Outputs, + Serializable, +) +from .mixins import LinkableMixin, OutputableMixin, RoutableMixin + +if TYPE_CHECKING: + from .pipeline import DesignerPipeline + + +class AssetNode(Node[TI, TO], LinkableMixin, OutputableMixin): + """ + Asset node class, this node will be used to fetch the asset from the + aixplain platform and use it in the pipeline. + + `assetId` is required and will be used to fetch the asset from the + aixplain platform. + + Input and output parameters will be automatically added based on the + asset function spec. + """ + + asset_id: Union[Model, str] = None + function: str = None + supplier: str = None + version: str = None + assetType: AssetType = AssetType.MODEL + functionType: FunctionType = FunctionType.AI + + type: NodeType = NodeType.ASSET + + def __init__( + self, + asset_id: Union[Model, str] = None, + supplier: str = None, + version: str = None, + pipeline: "DesignerPipeline" = None, + ): + super().__init__(pipeline=pipeline) + self.asset_id = asset_id + self.supplier = supplier + self.version = version + + if self.asset_id: + self.populate_asset() + + def populate_asset(self): + from aixplain.factories.model_factory import ModelFactory + + if isinstance(self.asset_id, str): + self.asset = ModelFactory.get(self.asset_id) + elif isinstance(self.asset_id, Model): + self.asset = self.asset_id + self.asset_id = self.asset_id.id + else: + raise ValueError("assetId should be a string or an Asset instance") + + try: + self.supplier = self.asset.supplier.value["code"] + except Exception: + self.supplier = str(self.asset.supplier) + + self.version = self.asset.version + + if self.function: + if self.asset.function.value != self.function: + raise ValueError( + f"Function {self.function} is not supported by asset {self.asset_id}" + ) # noqa + else: + self.function = self.asset.function.value + self._auto_populate_params() + + self._auto_set_params() + + def _auto_populate_params(self): + from aixplain.enums.function import FunctionInputOutput + + spec = FunctionInputOutput[self.asset.function.value]["spec"] + for item in spec["params"]: + self.inputs.create_param( + code=item["code"], + data_type=item["dataType"], + is_required=item["required"], + ) + + for item in spec["output"]: + self.outputs.create_param( + code=item["code"], + data_type=item["dataType"], + ) + + def _auto_set_params(self): + for k, v in self.asset.additional_info["parameters"].items(): + if isinstance(v, list): + self.inputs[k] = v[0] + else: + self.inputs[k] = v + + def serialize(self) -> dict: + obj = super().serialize() + obj["function"] = self.function + obj["assetId"] = self.asset_id + obj["supplier"] = self.supplier + obj["version"] = self.version + obj["assetType"] = self.assetType + obj["functionType"] = self.functionType + obj["type"] = self.type + return obj + + +class InputInputs(Inputs): + pass + + +class InputOutputs(Outputs): + input: OutputParam = None + + def __init__(self, node: Node): + super().__init__(node) + self.input = self.create_param("input") + + +class Input(Node[InputInputs, InputOutputs], LinkableMixin, RoutableMixin): + """ + Input node class, this node will be used to input the data to the + pipeline. + + Input nodes has only one output parameter called `input`. + + `data` is a special convenient parameter that will be uploaded to the + aixplain platform and the link will be passed as the input to the node. + """ + + data_types: Optional[List[DataType]] = None + data: Optional[str] = None + type: NodeType = NodeType.INPUT + inputs_class: Type[TI] = InputInputs + outputs_class: Type[TO] = InputOutputs + + def __init__( + self, + data: Optional[str] = None, + data_types: Optional[List[DataType]] = None, + pipeline: "DesignerPipeline" = None, + ): + from aixplain.factories.file_factory import FileFactory + + super().__init__(pipeline=pipeline) + self.data_types = data_types or [] + self.data = data + + if self.data: + self.data = FileFactory.to_link(self.data, is_temp=True) + + def serialize(self) -> dict: + obj = super().serialize() + obj["data"] = self.data + obj["dataType"] = self.data_types + return obj + + +class OutputInputs(Inputs): + output: InputParam = None + + def __init__(self, node: Node): + super().__init__(node) + self.output = self.create_param("output") + + +class OutputOutputs(Outputs): + pass + + +class Output(Node[OutputInputs, OutputOutputs]): + """ + Output node class, this node will be used to output the result of the + pipeline. + + Output nodes has only one input parameter called `output`. + """ + + data_types: Optional[List[DataType]] = None + type: NodeType = NodeType.OUTPUT + inputs_class: Type[TI] = OutputInputs + outputs_class: Type[TO] = OutputOutputs + + def __init__( + self, + data_types: Optional[List[DataType]] = None, + pipeline: "DesignerPipeline" = None, + ): + super().__init__(pipeline=pipeline) + self.data_types = data_types or [] + + def serialize(self) -> dict: + obj = super().serialize() + obj["dataType"] = self.data_types + return obj + + +class Script(Node[TI, TO], LinkableMixin, OutputableMixin): + """ + Script node class, this node will be used to run a script on the input + data. + + `script_path` is a special convenient parameter that will be uploaded to + the aixplain platform and the link will be passed as the input to the node. + """ + + fileId: Optional[str] = None + script_path: Optional[str] = None + type: NodeType = NodeType.SCRIPT + + def __init__( + self, + pipeline: "DesignerPipeline" = None, + script_path: Optional[str] = None, + fileId: Optional[str] = None, + ): + from aixplain.factories.script_factory import ScriptFactory + + super().__init__(pipeline=pipeline) + + assert script_path or fileId, "script_path or fileId is required" + + if not fileId: + self.fileId = ScriptFactory.upload_script(script_path) + else: + self.fileId = fileId + + def serialize(self) -> dict: + obj = super().serialize() + obj["fileId"] = self.fileId + return obj + + +class Route(Serializable): + """ + Route class, this class will be used to route the input data to different + nodes based on the input data type. + """ + + value: DataType + path: List[Union[Node, int]] + operation: Operation + type: RouteType + + def __init__( + self, + value: DataType, + path: List[Union[Node, int]], + operation: Operation, + type: RouteType, + ): + """ + Post init method to convert the nodes to node numbers if they are + nodes. + """ + self.value = value + self.path = path + self.operation = operation + self.type = type + + if not self.path: + raise ValueError("Path is not valid, should be a list of nodes") + + # convert nodes to node numbers if they are nodes + self.path = [ + node.number if isinstance(node, Node) else node + for node in self.path + ] + + def serialize(self) -> dict: + return { + "value": self.value, + "path": self.path, + "operation": self.operation, + "type": self.type, + } + + +class RouterInputs(Inputs): + input: InputParam = None + + def __init__(self, node: Node): + super().__init__(node) + self.input = self.create_param("input") + + +class RouterOutputs(Outputs): + input: OutputParam = None + + def __init__(self, node: Node): + super().__init__(node) + self.input = self.create_param("input") + + +class Router(Node[RouterInputs, RouterOutputs], LinkableMixin): + """ + Router node class, this node will be used to route the input data to + different nodes based on the input data type. + """ + + routes: List[Route] + type: NodeType = NodeType.ROUTER + inputs_class: Type[TI] = RouterInputs + outputs_class: Type[TO] = RouterOutputs + + def __init__( + self, routes: List[Route], pipeline: "DesignerPipeline" = None + ): + super().__init__(pipeline=pipeline) + self.routes = routes + + def serialize(self) -> dict: + obj = super().serialize() + obj["routes"] = [route.serialize() for route in self.routes] + return obj + + +class DecisionInputs(Inputs): + comparison: InputParam = None + passthrough: InputParam = None + + def __init__(self, node: Node): + super().__init__(node) + self.comparison = self.create_param("comparison") + self.passthrough = self.create_param("passthrough") + + +class DecisionOutputs(Outputs): + input: OutputParam = None + + def __init__(self, node: Node): + super().__init__(node) + self.input = self.create_param("input") + + +class Decision(Node[DecisionInputs, DecisionOutputs], LinkableMixin): + """ + Decision node class, this node will be used to make decisions based on + the input data. + """ + + routes: List[Route] + type: NodeType = NodeType.DECISION + inputs_class: Type[TI] = DecisionInputs + outputs_class: Type[TO] = DecisionOutputs + + def __init__( + self, routes: List[Route], pipeline: "DesignerPipeline" = None + ): + super().__init__(pipeline=pipeline) + self.routes = routes + + def link( + self, + to_node: Node, + from_param: Union[str, Param], + to_param: Union[str, Param], + ) -> Link: + link = super().link(to_node, from_param, to_param) + self.outputs.input.data_type = self.inputs.passthrough.data_type + return link + + def serialize(self) -> dict: + obj = super().serialize() + obj["routes"] = [route.serialize() for route in self.routes] + return obj + + +class BaseSegmentor(AssetNode[TI, TO]): + """ + Segmentor node class, this node will be used to segment the input data + into smaller fragments for much easier and efficient processing. + """ + + type: NodeType = NodeType.SEGMENTOR + functionType: FunctionType = FunctionType.SEGMENTOR + + +class SegmentorInputs(Inputs): + pass + + +class SegmentorOutputs(Outputs): + audio: OutputParam = None + + def __init__(self, node: Node): + super().__init__(node) + self.audio = self.create_param("audio") + + +class BareSegmentor(BaseSegmentor[SegmentorInputs, SegmentorOutputs]): + """ + Segmentor node class, this node will be used to segment the input data + into smaller fragments for much easier and efficient processing. + """ + + type: NodeType = NodeType.SEGMENTOR + functionType: FunctionType = FunctionType.SEGMENTOR + inputs_class: Type[TI] = SegmentorInputs + outputs_class: Type[TO] = SegmentorOutputs + + +class BaseReconstructor(AssetNode[TI, TO]): + """ + Reconstructor node class, this node will be used to reconstruct the + output of the segmented lines of execution. + """ + + type: NodeType = NodeType.RECONSTRUCTOR + functionType: FunctionType = FunctionType.RECONSTRUCTOR + + +class ReconstructorInputs(Inputs): + data: InputParam = None + + def __init__(self, node: Node): + super().__init__(node) + self.data = self.create_param("data") + + +class ReconstructorOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node: Node): + super().__init__(node) + self.data = self.create_param("data") + + +class BareReconstructor( + BaseReconstructor[ReconstructorInputs, ReconstructorOutputs] +): + """ + Reconstructor node class, this node will be used to reconstruct the + output of the segmented lines of execution. + """ + + type: NodeType = NodeType.RECONSTRUCTOR + functionType: FunctionType = FunctionType.RECONSTRUCTOR + inputs_class: Type[TI] = ReconstructorInputs + outputs_class: Type[TO] = ReconstructorOutputs diff --git a/aixplain/modules/pipeline/designer/pipeline.py b/aixplain/modules/pipeline/designer/pipeline.py new file mode 100644 index 00000000..5304d202 --- /dev/null +++ b/aixplain/modules/pipeline/designer/pipeline.py @@ -0,0 +1,328 @@ +from typing import List, Type, Tuple, TypeVar + +from aixplain.enums import DataType + +from .base import Serializable, Node, Link +from .nodes import ( + AssetNode, + Decision, + Script, + Input, + Output, + Router, + Route, + BareReconstructor, + BareSegmentor, +) +from .enums import NodeType, RouteType, Operation + + +T = TypeVar("T", bound="AssetNode") + + +class DesignerPipeline(Serializable): + nodes: List[Node] = None + links: List[Link] = None + instance: any = None + + def __init__(self): + self.nodes = [] + self.links = [] + + def add_node(self, node: Node): + """ + Add a node to the current pipeline. + + This method will take care of setting the pipeline instance to the + node and setting the node number if it's not set. + + :param node: the node + :return: the node + """ + return node.attach_to(self) + + def add_nodes(self, *nodes: Node) -> List[Node]: + """ + Add multiple nodes to the current pipeline. + + :param nodes: the nodes + :return: the nodes + """ + return [self.add_node(node) for node in nodes] + + def add_link(self, link: Link) -> Link: + """ + Add a link to the current pipeline. + :param link: the link + :return: the link + """ + return link.attach_to(self) + + def serialize(self) -> dict: + """ + Serialize the pipeline to a dictionary. This method will serialize the + pipeline to a dictionary. + + :return: the pipeline as a dictionary + """ + return { + "nodes": [node.serialize() for node in self.nodes], + "links": [link.serialize() for link in self.links], + } + + def validate_nodes(self): + """ + Validate the linkage of the pipeline. This method will validate the + linkage of the pipeline by applying the following checks: + - All input nodes are linked out + - All output nodes are linked in + - All other nodes are linked in and out + + :raises ValueError: if the pipeline is not valid + """ + link_from_map = {link.from_node.number: link for link in self.links} + link_to_map = {link.to_node.number: link for link in self.links} + contains_input = False + contains_output = False + contains_asset = False + for node in self.nodes: + # validate every input node is linked out + if node.type == NodeType.INPUT: + contains_input = True + if node.number not in link_from_map: + raise ValueError(f"Input node {node.label} not linked out") + # validate every output node is linked in + elif node.type == NodeType.OUTPUT: + contains_output = True + if node.number not in link_to_map: + raise ValueError(f"Output node {node.label} not linked in") + # validate rest of the nodes are linked in and out + else: + if isinstance(node, AssetNode): + contains_asset = True + if node.number not in link_from_map: + raise ValueError(f"Node {node.label} not linked in") + if node.number not in link_to_map: + raise ValueError(f"Node {node.label} not linked out") + + if not contains_input or not contains_output or not contains_asset: + raise ValueError( + "Pipeline must contain at least one input, output and asset node" # noqa + ) + + def is_param_linked(self, node, param): + """ + Check if the param is linked to another node. This method will check + if the param is linked to another node. + :param node: the node + :param param: the param + :return: True if the param is linked, False otherwise + """ + for link in self.links: + if ( + link.to_node.number == node.number + and param.code == link.to_param + ): + return True + + return False + + def is_param_set(self, node, param): + """ + Check if the param is set. This method will check if the param is set + or linked to another node. + :param node: the node + :param param: the param + :return: True if the param is set, False otherwise + """ + return param.value or self.is_param_linked(node, param) + + def validate_params(self): + """ + This method will check if all required params are either set or linked + + :raises ValueError: if the pipeline is not valid + """ + for node in self.nodes: + for param in node.inputs: + if param.is_required and not self.is_param_set(node, param): + raise ValueError( + f"Param {param.code} of node {node.label} is required" + ) + + def validate(self): + """ + Validate the pipeline. This method will validate the pipeline by + series of checks: + - Validate all nodes are linked correctly + - Validate all required params are set or linked + + Any other validation checks can be added here. + + :raises ValueError: if the pipeline is not valid + """ + self.validate_nodes() + self.validate_params() + + def get_link(self, from_node: int, to_node: int) -> Link: + """ + Get the link between two nodes. This method will return the link + between two nodes. + + :param from_node: the from node number + :param to_node: the to node number + :return: the link + """ + return next( + ( + link + for link in self.links + if link.from_node == from_node and link.to_node == to_node + ), + None, + ) + + def get_node(self, node_number: int) -> Node: + """ + Get the node by its number. This method will return the node with the + given number. + + :param node_number: the node number + :return: the node + """ + return next( + (node for node in self.nodes if node.number == node_number), None + ) + + def auto_infer(self): + """ + Automatically infer the data types of the nodes in the pipeline. + This method will automatically infer the data types of the nodes in the + pipeline by traversing the pipeline and setting the data types of the + nodes based on the data types of the connected nodes. + """ + for link in self.links: + from_node = self.get_node(link.from_node) + to_node = self.get_node(link.to_node) + if not from_node or not to_node: + continue # will be handled by the validation + for param in link.param_mapping: + from_param = from_node.outputs[param.from_param] + to_param = to_node.inputs[param.to_param] + if not from_param or not to_param: + continue # will be handled by the validation + # if one of the data types is missing, infer the other one + dataType = from_param.data_type or to_param.data_type + from_param.data_type = dataType + to_param.data_type = dataType + + def infer_data_type(node): + from .nodes import Input, Output + + if isinstance(node, Input) or isinstance(node, Output): + if dataType and dataType not in node.data_types: + node.data_types.append(dataType) + + infer_data_type(self) + infer_data_type(to_node) + + def asset( + self, asset_id: str, *args, asset_class: Type[T] = AssetNode, **kwargs + ) -> T: + """ + Shortcut to create an asset node for the current pipeline. + All params will be passed as keyword arguments to the node + constructor. + + :param kwargs: keyword arguments + :return: the node + """ + return asset_class(asset_id, *args, pipeline=self, **kwargs) + + def decision(self, *args, **kwargs) -> Decision: + """ + Shortcut to create an decision node for the current pipeline. + All params will be passed as keyword arguments to the node + constructor. + + :param kwargs: keyword arguments + :return: the node + """ + return Decision(*args, pipeline=self, **kwargs) + + def script(self, *args, **kwargs) -> Script: + """ + Shortcut to create an script node for the current pipeline. + All params will be passed as keyword arguments to the node + constructor. + + :param kwargs: keyword arguments + :return: the node + """ + return Script(*args, pipeline=self, **kwargs) + + def input(self, *args, **kwargs) -> Input: + """ + Shortcut to create an input node for the current pipeline. + All params will be passed as keyword arguments to the node + constructor. + + :param kwargs: keyword arguments + :return: the node + """ + return Input(*args, pipeline=self, **kwargs) + + def output(self, *args, **kwargs) -> Output: + """ + Shortcut to create an output node for the current pipeline. + All params will be passed as keyword arguments to the node + constructor. + + :param kwargs: keyword arguments + :return: the node + """ + return Output(*args, pipeline=self, **kwargs) + + def router(self, routes: Tuple[DataType, Node], *args, **kwargs) -> Router: + """ + Shortcut to create an decision node for the current pipeline. + All params will be passed as keyword arguments to the node + constructor. The routes will be handled specially and will be + converted to Route instances in a convenient way. + + :param routes: the routes + :param kwargs: keyword arguments + :return: the node + """ + kwargs["routes"] = [ + Route( + value=route[0], + path=[route[1]], + type=RouteType.CHECK_TYPE, + operation=Operation.EQUAL, + ) + for route in routes + ] + return Router(*args, pipeline=self, **kwargs) + + def bare_reconstructor(self, *args, **kwargs) -> BareReconstructor: + """ + Shortcut to create an reconstructor node for the current pipeline. + All params will be passed as keyword arguments to the node + constructor. + + :param kwargs: keyword arguments + :return: the node + """ + return BareReconstructor(*args, pipeline=self, **kwargs) + + def bare_segmentor(self, *args, **kwargs) -> BareSegmentor: + """ + Shortcut to create an segmentor node for the current pipeline. + All params will be passed as keyword arguments to the node + constructor. + + :param kwargs: keyword arguments + :return: the node + """ + return BareSegmentor(*args, pipeline=self, **kwargs) diff --git a/aixplain/modules/pipeline/generate.py b/aixplain/modules/pipeline/generate.py new file mode 100644 index 00000000..c71e8ae6 --- /dev/null +++ b/aixplain/modules/pipeline/generate.py @@ -0,0 +1,227 @@ +import pathlib + +import requests +from urllib.parse import urljoin +from jinja2 import Environment, BaseLoader + +from aixplain.utils import config + +SEGMENTOR_FUNCTIONS = [ + "split-on-linebreak", + "speaker-diarization-audio", + "voice-activity-detection", +] + +RECONSTRUCTOR_FUNCTIONS = ["text-reconstruction", "audio-reconstruction"] + +MODULE_NAME = "pipeline" +TEMPLATE = """# This is an auto generated module. PLEASE DO NOT EDIT + + +from typing import Union, Type +from aixplain.enums import DataType + +from .designer import ( + InputParam, + OutputParam, + Inputs, + Outputs, + TI, + TO, + AssetNode, + BaseReconstructor, + BaseSegmentor, +) +from .default import DefaultPipeline +from aixplain.modules import asset + +{% for spec in specs %} + +class {{ spec.class_name }}Inputs(Inputs): +{% for input in spec.inputs %} + {{ input.name }}: InputParam = None +{% endfor %} + + def __init__(self, node=None): + super().__init__(node=node) +{% for input in spec.inputs %} + self.{{ input.name }} = self.create_param(code="{{ input.name }}", data_type=DataType.{{ input.data_type | upper }}, is_required={{ input.is_required }}) +{% endfor %} + + +class {{ spec.class_name }}Outputs(Outputs): +{% for output in spec.outputs %} + {{ output.name }}: OutputParam = None +{% endfor %} +{% if spec.is_segmentor %} + audio: OutputParam = None +{% endif %} + + def __init__(self, node=None): + super().__init__(node=node) +{% for output in spec.outputs %} + self.{{ output.name }} = self.create_param(code="{{ output.name }}", data_type=DataType.{{ output.data_type | upper }}) +{% endfor %} +{% if spec.is_segmentor %} + self.audio = self.create_param(code="audio", data_type=DataType.AUDIO) +{% endif %} + + +class {{ spec.class_name }}({{spec.base_class}}[{{ spec.class_name }}Inputs, {{ spec.class_name }}Outputs]): + \"\"\" + {{ spec.description | wordwrap }} + + InputType: {{ spec.input_type }} + OutputType: {{ spec.output_type }} + \"\"\" + function: str = "{{ spec.id }}" + input_type: str = DataType.{{ spec.input_type | upper }} + output_type: str = DataType.{{ spec.output_type | upper }} + + inputs_class: Type[TI] = {{ spec.class_name }}Inputs + outputs_class: Type[TO] = {{ spec.class_name }}Outputs + +{% endfor %} + + +class Pipeline(DefaultPipeline): + +{% for spec in specs %} + def {{ spec.function_name }}(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> {{ spec.class_name }}: + \"\"\" + {{ spec.description | wordwrap }} + \"\"\" + return {{ spec.class_name }}(*args, asset_id=asset_id, pipeline=self, **kwargs) + +{% endfor %} +""" + + +def fetch_functions(): + """ + Fetch functions from the backend + """ + api_key = config.TEAM_API_KEY + aixplain_key = config.AIXPLAIN_API_KEY + backend_url = config.BACKEND_URL + + url = urljoin(backend_url, "sdk/functions") + headers = { + "Content-Type": "application/json", + } + + if aixplain_key: + headers["x-aixplain-key"] = aixplain_key + else: + headers["x-api-key"] = api_key + + r = requests.get(url, headers=headers) + try: + r.raise_for_status() + except requests.exceptions.HTTPError as e: + print("Functions could not be loaded, see error below") + raise e + + resp = r.json() + return resp["items"] + + +def populate_data_types(functions: list): + """ + Populate the data types + """ + data_types = set() + for function in functions: + for param in function["params"]: + data_types.add(param["dataType"]) + for output in function["output"]: + data_types.add(output["dataType"]) + return data_types + + +def populate_specs(functions: list): + """ + Populate the function class specs + """ + function_class_specs = [] + for function in functions: + # slugify function name by trimming some special chars and + # transforming it to snake case + function_name = ( + function["id"] + .replace("-", "_") + .replace("(", "_") + .replace(")", "_") + ) + base_class = "AssetNode" + is_segmentor = function["id"] in SEGMENTOR_FUNCTIONS + is_reconstructor = function["id"] in RECONSTRUCTOR_FUNCTIONS + if is_segmentor: + base_class = "BaseSegmentor" + elif is_reconstructor: + base_class = "BaseReconstructor" + + spec = { + "id": function["id"], + "is_segmentor": function["id"] in SEGMENTOR_FUNCTIONS, + "is_reconstructor": function["id"] in RECONSTRUCTOR_FUNCTIONS, + "function_name": function_name, + "base_class": base_class, + "class_name": "".join( + [w.title() for w in function_name.split("_")] + ), + "description": function["metaData"]["description"], + "input_type": function["metaData"]["InputType"], + "output_type": function["metaData"]["OutputType"], + "inputs": [ + { + "name": param["code"], + "data_type": param["dataType"], + "is_required": param["required"], + "is_list": param.get("multipleValues", False), + "default": param.get("defaultValues"), + "is_fixed": param.get("isFixed", False), + } + for param in function["params"] + ], + "outputs": [ + { + "name": output["code"], + "data_type": output["dataType"], + "default": output.get("defaultValue"), + } + for output in function["output"] + ], + } + + function_class_specs.append(spec) + + return function_class_specs + + +if __name__ == "__main__": + print("Fetching function specs") + + functions = fetch_functions() + data_types = populate_data_types(functions) + specs = populate_specs(functions) + + print( + f"Populating module with {len(data_types)} data types and {len(specs)} specs" + ) + env = Environment( + loader=BaseLoader(), + trim_blocks=True, + lstrip_blocks=True, + ) + template = env.from_string(TEMPLATE) + output = template.render(data_types=data_types, specs=specs) + + current_dir = pathlib.Path(__file__).parent + file_path = current_dir / f"{MODULE_NAME}.py" + + print(f"Writing module to file: {file_path}") + with open(file_path, "w") as f: + f.write(output) + + print("Module generated successfully") diff --git a/aixplain/modules/pipeline/pipeline.py b/aixplain/modules/pipeline/pipeline.py new file mode 100644 index 00000000..36bc643d --- /dev/null +++ b/aixplain/modules/pipeline/pipeline.py @@ -0,0 +1,4548 @@ +# This is an auto generated module. PLEASE DO NOT EDIT + + +from typing import Union, Type +from aixplain.enums import DataType + +from .designer import ( + InputParam, + OutputParam, + Inputs, + Outputs, + TI, + TO, + AssetNode, + BaseReconstructor, + BaseSegmentor, +) +from .default import DefaultPipeline +from aixplain.modules import asset + + +class ObjectDetectionInputs(Inputs): + image: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.image = self.create_param(code="image", data_type=DataType.IMAGE, is_required=True) + + +class ObjectDetectionOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class ObjectDetection(AssetNode[ObjectDetectionInputs, ObjectDetectionOutputs]): + """ + Object Detection is a computer vision technology that identifies and locates +objects within an image, typically by drawing bounding boxes around the +detected objects and classifying them into predefined categories. + + InputType: video + OutputType: text + """ + function: str = "object-detection" + input_type: str = DataType.VIDEO + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = ObjectDetectionInputs + outputs_class: Type[TO] = ObjectDetectionOutputs + + +class LanguageIdentificationInputs(Inputs): + text: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + + +class LanguageIdentificationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class LanguageIdentification(AssetNode[LanguageIdentificationInputs, LanguageIdentificationOutputs]): + """ + Language Identification is the process of automatically determining the +language in which a given piece of text is written. + + InputType: text + OutputType: text + """ + function: str = "language-identification" + input_type: str = DataType.TEXT + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = LanguageIdentificationInputs + outputs_class: Type[TO] = LanguageIdentificationOutputs + + +class OcrInputs(Inputs): + image: InputParam = None + featuretypes: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.image = self.create_param(code="image", data_type=DataType.IMAGE, is_required=True) + self.featuretypes = self.create_param(code="featuretypes", data_type=DataType.TEXT, is_required=True) + + +class OcrOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class Ocr(AssetNode[OcrInputs, OcrOutputs]): + """ + OCR, or Optical Character Recognition, is a technology that converts different +types of documents, such as scanned paper documents, PDFs, or images captured +by a digital camera, into editable and searchable data by recognizing and +extracting text from the images. + + InputType: image + OutputType: text + """ + function: str = "ocr" + input_type: str = DataType.IMAGE + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = OcrInputs + outputs_class: Type[TO] = OcrOutputs + + +class ScriptExecutionInputs(Inputs): + text: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + + +class ScriptExecutionOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class ScriptExecution(AssetNode[ScriptExecutionInputs, ScriptExecutionOutputs]): + """ + Script Execution refers to the process of running a set of programmed +instructions or code within a computing environment, enabling the automated +performance of tasks, calculations, or operations as defined by the script. + + InputType: text + OutputType: text + """ + function: str = "script-execution" + input_type: str = DataType.TEXT + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = ScriptExecutionInputs + outputs_class: Type[TO] = ScriptExecutionOutputs + + +class ImageLabelDetectionInputs(Inputs): + image: InputParam = None + min_confidence: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.image = self.create_param(code="image", data_type=DataType.IMAGE, is_required=True) + self.min_confidence = self.create_param(code="min_confidence", data_type=DataType.TEXT, is_required=False) + + +class ImageLabelDetectionOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class ImageLabelDetection(AssetNode[ImageLabelDetectionInputs, ImageLabelDetectionOutputs]): + """ + Image Label Detection is a function that automatically identifies and assigns +descriptive tags or labels to objects, scenes, or elements within an image, +enabling easier categorization, search, and analysis of visual content. + + InputType: image + OutputType: label + """ + function: str = "image-label-detection" + input_type: str = DataType.IMAGE + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = ImageLabelDetectionInputs + outputs_class: Type[TO] = ImageLabelDetectionOutputs + + +class ImageCaptioningInputs(Inputs): + image: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.image = self.create_param(code="image", data_type=DataType.IMAGE, is_required=True) + + +class ImageCaptioningOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class ImageCaptioning(AssetNode[ImageCaptioningInputs, ImageCaptioningOutputs]): + """ + Image Captioning is a process that involves generating a textual description of +an image, typically using machine learning models to analyze the visual content +and produce coherent and contextually relevant sentences that describe the +objects, actions, and scenes depicted in the image. + + InputType: image + OutputType: text + """ + function: str = "image-captioning" + input_type: str = DataType.IMAGE + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = ImageCaptioningInputs + outputs_class: Type[TO] = ImageCaptioningOutputs + + +class AudioLanguageIdentificationInputs(Inputs): + audio: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.audio = self.create_param(code="audio", data_type=DataType.AUDIO, is_required=True) + + +class AudioLanguageIdentificationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class AudioLanguageIdentification(AssetNode[AudioLanguageIdentificationInputs, AudioLanguageIdentificationOutputs]): + """ + Audio Language Identification is a process that involves analyzing an audio +recording to determine the language being spoken. + + InputType: audio + OutputType: label + """ + function: str = "audio-language-identification" + input_type: str = DataType.AUDIO + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = AudioLanguageIdentificationInputs + outputs_class: Type[TO] = AudioLanguageIdentificationOutputs + + +class AsrAgeClassificationInputs(Inputs): + source_audio: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.source_audio = self.create_param(code="source_audio", data_type=DataType.AUDIO, is_required=True) + + +class AsrAgeClassificationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class AsrAgeClassification(AssetNode[AsrAgeClassificationInputs, AsrAgeClassificationOutputs]): + """ + The ASR Age Classification function is designed to analyze audio recordings of +speech to determine the speaker's age group by leveraging automatic speech +recognition (ASR) technology and machine learning algorithms. + + InputType: audio + OutputType: label + """ + function: str = "asr-age-classification" + input_type: str = DataType.AUDIO + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = AsrAgeClassificationInputs + outputs_class: Type[TO] = AsrAgeClassificationOutputs + + +class BenchmarkScoringMtInputs(Inputs): + input: InputParam = None + text: InputParam = None + text: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.input = self.create_param(code="input", data_type=DataType.TEXT, is_required=True) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + + +class BenchmarkScoringMtOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class BenchmarkScoringMt(AssetNode[BenchmarkScoringMtInputs, BenchmarkScoringMtOutputs]): + """ + Benchmark Scoring MT is a function designed to evaluate and score machine +translation systems by comparing their output against a set of predefined +benchmarks, thereby assessing their accuracy and performance. + + InputType: text + OutputType: label + """ + function: str = "benchmark-scoring-mt" + input_type: str = DataType.TEXT + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = BenchmarkScoringMtInputs + outputs_class: Type[TO] = BenchmarkScoringMtOutputs + + +class AsrGenderClassificationInputs(Inputs): + source_audio: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.source_audio = self.create_param(code="source_audio", data_type=DataType.AUDIO, is_required=True) + + +class AsrGenderClassificationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class AsrGenderClassification(AssetNode[AsrGenderClassificationInputs, AsrGenderClassificationOutputs]): + """ + The ASR Gender Classification function analyzes audio recordings to determine +and classify the speaker's gender based on their voice characteristics. + + InputType: audio + OutputType: label + """ + function: str = "asr-gender-classification" + input_type: str = DataType.AUDIO + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = AsrGenderClassificationInputs + outputs_class: Type[TO] = AsrGenderClassificationOutputs + + +class BaseModelInputs(Inputs): + language: InputParam = None + text: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + + +class BaseModelOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class BaseModel(AssetNode[BaseModelInputs, BaseModelOutputs]): + """ + The Base-Model function serves as a foundational framework designed to provide +essential features and capabilities upon which more specialized or advanced +models can be built and customized. + + InputType: text + OutputType: text + """ + function: str = "base-model" + input_type: str = DataType.TEXT + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = BaseModelInputs + outputs_class: Type[TO] = BaseModelOutputs + + +class LanguageIdentificationAudioInputs(Inputs): + audio: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.audio = self.create_param(code="audio", data_type=DataType.AUDIO, is_required=True) + + +class LanguageIdentificationAudioOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class LanguageIdentificationAudio(AssetNode[LanguageIdentificationAudioInputs, LanguageIdentificationAudioOutputs]): + """ + The Language Identification Audio function analyzes audio input to determine +and identify the language being spoken. + + InputType: audio + OutputType: label + """ + function: str = "language-identification-audio" + input_type: str = DataType.AUDIO + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = LanguageIdentificationAudioInputs + outputs_class: Type[TO] = LanguageIdentificationAudioOutputs + + +class LoglikelihoodInputs(Inputs): + text: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + + +class LoglikelihoodOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.NUMBER) + + +class Loglikelihood(AssetNode[LoglikelihoodInputs, LoglikelihoodOutputs]): + """ + The Log Likelihood function measures the probability of observing the given +data under a specific statistical model by taking the natural logarithm of the +likelihood function, thereby transforming the product of probabilities into a +sum, which simplifies the process of optimization and parameter estimation. + + InputType: text + OutputType: number + """ + function: str = "loglikelihood" + input_type: str = DataType.TEXT + output_type: str = DataType.NUMBER + + inputs_class: Type[TI] = LoglikelihoodInputs + outputs_class: Type[TO] = LoglikelihoodOutputs + + +class VideoEmbeddingInputs(Inputs): + language: InputParam = None + video: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.video = self.create_param(code="video", data_type=DataType.VIDEO, is_required=False) + + +class VideoEmbeddingOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.EMBEDDING) + + +class VideoEmbedding(AssetNode[VideoEmbeddingInputs, VideoEmbeddingOutputs]): + """ + Video Embedding is a process that transforms video content into a fixed- +dimensional vector representation, capturing essential features and patterns to +facilitate tasks such as retrieval, classification, and recommendation. + + InputType: video + OutputType: embedding + """ + function: str = "video-embedding" + input_type: str = DataType.VIDEO + output_type: str = DataType.EMBEDDING + + inputs_class: Type[TI] = VideoEmbeddingInputs + outputs_class: Type[TO] = VideoEmbeddingOutputs + + +class TextSegmenationInputs(Inputs): + text: InputParam = None + language: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + + +class TextSegmenationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class TextSegmenation(AssetNode[TextSegmenationInputs, TextSegmenationOutputs]): + """ + Text Segmentation is the process of dividing a continuous text into meaningful +units, such as words, sentences, or topics, to facilitate easier analysis and +understanding. + + InputType: text + OutputType: text + """ + function: str = "text-segmenation" + input_type: str = DataType.TEXT + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = TextSegmenationInputs + outputs_class: Type[TO] = TextSegmenationOutputs + + +class ImageEmbeddingInputs(Inputs): + language: InputParam = None + image: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.image = self.create_param(code="image", data_type=DataType.IMAGE, is_required=False) + + +class ImageEmbeddingOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class ImageEmbedding(AssetNode[ImageEmbeddingInputs, ImageEmbeddingOutputs]): + """ + Image Embedding is a process that transforms an image into a fixed-dimensional +vector representation, capturing its essential features and enabling efficient +comparison, retrieval, and analysis in various machine learning and computer +vision tasks. + + InputType: image + OutputType: text + """ + function: str = "image-embedding" + input_type: str = DataType.IMAGE + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = ImageEmbeddingInputs + outputs_class: Type[TO] = ImageEmbeddingOutputs + + +class ImageManipulationInputs(Inputs): + image: InputParam = None + targetimage: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.image = self.create_param(code="image", data_type=DataType.IMAGE, is_required=True) + self.targetimage = self.create_param(code="targetimage", data_type=DataType.IMAGE, is_required=True) + + +class ImageManipulationOutputs(Outputs): + image: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.image = self.create_param(code="image", data_type=DataType.IMAGE) + + +class ImageManipulation(AssetNode[ImageManipulationInputs, ImageManipulationOutputs]): + """ + Image Manipulation refers to the process of altering or enhancing digital +images using various techniques and tools to achieve desired visual effects, +correct imperfections, or transform the image's appearance. + + InputType: image + OutputType: image + """ + function: str = "image-manipulation" + input_type: str = DataType.IMAGE + output_type: str = DataType.IMAGE + + inputs_class: Type[TI] = ImageManipulationInputs + outputs_class: Type[TO] = ImageManipulationOutputs + + +class ImageToVideoGenerationInputs(Inputs): + language: InputParam = None + image: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.image = self.create_param(code="image", data_type=DataType.IMAGE, is_required=False) + + +class ImageToVideoGenerationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.VIDEO) + + +class ImageToVideoGeneration(AssetNode[ImageToVideoGenerationInputs, ImageToVideoGenerationOutputs]): + """ + The Image To Video Generation function transforms a series of static images +into a cohesive, dynamic video sequence, often incorporating transitions, +effects, and synchronization with audio to create a visually engaging +narrative. + + InputType: image + OutputType: video + """ + function: str = "image-to-video-generation" + input_type: str = DataType.IMAGE + output_type: str = DataType.VIDEO + + inputs_class: Type[TI] = ImageToVideoGenerationInputs + outputs_class: Type[TO] = ImageToVideoGenerationOutputs + + +class AudioForcedAlignmentInputs(Inputs): + audio: InputParam = None + text: InputParam = None + language: InputParam = None + dialect: InputParam = None + script: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.audio = self.create_param(code="audio", data_type=DataType.AUDIO, is_required=True) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.dialect = self.create_param(code="dialect", data_type=DataType.LABEL, is_required=False) + self.script = self.create_param(code="script", data_type=DataType.LABEL, is_required=False) + + +class AudioForcedAlignmentOutputs(Outputs): + text: OutputParam = None + audio: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT) + self.audio = self.create_param(code="audio", data_type=DataType.AUDIO) + + +class AudioForcedAlignment(AssetNode[AudioForcedAlignmentInputs, AudioForcedAlignmentOutputs]): + """ + Audio Forced Alignment is a process that synchronizes a given audio recording +with its corresponding transcript by precisely aligning each spoken word or +phoneme to its exact timing within the audio. + + InputType: audio + OutputType: audio + """ + function: str = "audio-forced-alignment" + input_type: str = DataType.AUDIO + output_type: str = DataType.AUDIO + + inputs_class: Type[TI] = AudioForcedAlignmentInputs + outputs_class: Type[TO] = AudioForcedAlignmentOutputs + + +class BenchmarkScoringAsrInputs(Inputs): + input: InputParam = None + text: InputParam = None + text: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.input = self.create_param(code="input", data_type=DataType.AUDIO, is_required=True) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + + +class BenchmarkScoringAsrOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class BenchmarkScoringAsr(AssetNode[BenchmarkScoringAsrInputs, BenchmarkScoringAsrOutputs]): + """ + Benchmark Scoring ASR is a function that evaluates and compares the performance +of automatic speech recognition systems by analyzing their accuracy, speed, and +other relevant metrics against a standardized set of benchmarks. + + InputType: audio + OutputType: label + """ + function: str = "benchmark-scoring-asr" + input_type: str = DataType.AUDIO + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = BenchmarkScoringAsrInputs + outputs_class: Type[TO] = BenchmarkScoringAsrOutputs + + +class VisualQuestionAnsweringInputs(Inputs): + text: InputParam = None + language: InputParam = None + image: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.image = self.create_param(code="image", data_type=DataType.IMAGE, is_required=False) + + +class VisualQuestionAnsweringOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class VisualQuestionAnswering(AssetNode[VisualQuestionAnsweringInputs, VisualQuestionAnsweringOutputs]): + """ + Visual Question Answering (VQA) is a task in artificial intelligence that +involves analyzing an image and providing accurate, contextually relevant +answers to questions posed about the visual content of that image. + + InputType: image + OutputType: video + """ + function: str = "visual-question-answering" + input_type: str = DataType.IMAGE + output_type: str = DataType.VIDEO + + inputs_class: Type[TI] = VisualQuestionAnsweringInputs + outputs_class: Type[TO] = VisualQuestionAnsweringOutputs + + +class DocumentImageParsingInputs(Inputs): + image: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.image = self.create_param(code="image", data_type=DataType.IMAGE, is_required=False) + + +class DocumentImageParsingOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class DocumentImageParsing(AssetNode[DocumentImageParsingInputs, DocumentImageParsingOutputs]): + """ + Document Image Parsing is the process of analyzing and converting scanned or +photographed images of documents into structured, machine-readable formats by +identifying and extracting text, layout, and other relevant information. + + InputType: image + OutputType: text + """ + function: str = "document-image-parsing" + input_type: str = DataType.IMAGE + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = DocumentImageParsingInputs + outputs_class: Type[TO] = DocumentImageParsingOutputs + + +class DocumentInformationExtractionInputs(Inputs): + image: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.image = self.create_param(code="image", data_type=DataType.IMAGE, is_required=False) + + +class DocumentInformationExtractionOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class DocumentInformationExtraction(AssetNode[DocumentInformationExtractionInputs, DocumentInformationExtractionOutputs]): + """ + Document Information Extraction is the process of automatically identifying, +extracting, and structuring relevant data from unstructured or semi-structured +documents, such as invoices, receipts, contracts, and forms, to facilitate +easier data management and analysis. + + InputType: image + OutputType: text + """ + function: str = "document-information-extraction" + input_type: str = DataType.IMAGE + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = DocumentInformationExtractionInputs + outputs_class: Type[TO] = DocumentInformationExtractionOutputs + + +class DepthEstimationInputs(Inputs): + language: InputParam = None + image: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.image = self.create_param(code="image", data_type=DataType.IMAGE, is_required=False) + + +class DepthEstimationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class DepthEstimation(AssetNode[DepthEstimationInputs, DepthEstimationOutputs]): + """ + Depth estimation is a computational process that determines the distance of +objects from a viewpoint, typically using visual data from cameras or sensors +to create a three-dimensional understanding of a scene. + + InputType: image + OutputType: text + """ + function: str = "depth-estimation" + input_type: str = DataType.IMAGE + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = DepthEstimationInputs + outputs_class: Type[TO] = DepthEstimationOutputs + + +class VideoGenerationInputs(Inputs): + text: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + + +class VideoGenerationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.VIDEO) + + +class VideoGeneration(AssetNode[VideoGenerationInputs, VideoGenerationOutputs]): + """ + Video Generation is the process of creating video content through automated or +semi-automated means, often utilizing algorithms, artificial intelligence, or +software tools to produce visual and audio elements that can range from simple +animations to complex, realistic scenes. + + InputType: text + OutputType: video + """ + function: str = "video-generation" + input_type: str = DataType.TEXT + output_type: str = DataType.VIDEO + + inputs_class: Type[TI] = VideoGenerationInputs + outputs_class: Type[TO] = VideoGenerationOutputs + + +class ReferencelessAudioGenerationMetricInputs(Inputs): + hypotheses: InputParam = None + sources: InputParam = None + score_identifier: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.hypotheses = self.create_param(code="hypotheses", data_type=DataType.AUDIO, is_required=True) + self.sources = self.create_param(code="sources", data_type=DataType.AUDIO, is_required=False) + self.score_identifier = self.create_param(code="score_identifier", data_type=DataType.TEXT, is_required=True) + + +class ReferencelessAudioGenerationMetricOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class ReferencelessAudioGenerationMetric(AssetNode[ReferencelessAudioGenerationMetricInputs, ReferencelessAudioGenerationMetricOutputs]): + """ + The Referenceless Audio Generation Metric is a tool designed to evaluate the +quality of generated audio content without the need for a reference or original +audio sample for comparison. + + InputType: text + OutputType: text + """ + function: str = "referenceless-audio-generation-metric" + input_type: str = DataType.TEXT + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = ReferencelessAudioGenerationMetricInputs + outputs_class: Type[TO] = ReferencelessAudioGenerationMetricOutputs + + +class MultiClassImageClassificationInputs(Inputs): + image: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.image = self.create_param(code="image", data_type=DataType.IMAGE, is_required=False) + + +class MultiClassImageClassificationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class MultiClassImageClassification(AssetNode[MultiClassImageClassificationInputs, MultiClassImageClassificationOutputs]): + """ + Multi Class Image Classification is a machine learning task where an algorithm +is trained to categorize images into one of several predefined classes or +categories based on their visual content. + + InputType: image + OutputType: label + """ + function: str = "multi-class-image-classification" + input_type: str = DataType.IMAGE + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = MultiClassImageClassificationInputs + outputs_class: Type[TO] = MultiClassImageClassificationOutputs + + +class SemanticSegmentationInputs(Inputs): + image: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.image = self.create_param(code="image", data_type=DataType.IMAGE, is_required=False) + + +class SemanticSegmentationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class SemanticSegmentation(AssetNode[SemanticSegmentationInputs, SemanticSegmentationOutputs]): + """ + Semantic segmentation is a computer vision process that involves classifying +each pixel in an image into a predefined category, effectively partitioning the +image into meaningful segments based on the objects or regions they represent. + + InputType: image + OutputType: label + """ + function: str = "semantic-segmentation" + input_type: str = DataType.IMAGE + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = SemanticSegmentationInputs + outputs_class: Type[TO] = SemanticSegmentationOutputs + + +class InstanceSegmentationInputs(Inputs): + image: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.image = self.create_param(code="image", data_type=DataType.IMAGE, is_required=False) + + +class InstanceSegmentationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class InstanceSegmentation(AssetNode[InstanceSegmentationInputs, InstanceSegmentationOutputs]): + """ + Instance segmentation is a computer vision task that involves detecting and +delineating each distinct object within an image, assigning a unique label and +precise boundary to every individual instance of objects, even if they belong +to the same category. + + InputType: image + OutputType: label + """ + function: str = "instance-segmentation" + input_type: str = DataType.IMAGE + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = InstanceSegmentationInputs + outputs_class: Type[TO] = InstanceSegmentationOutputs + + +class ImageColorizationInputs(Inputs): + image: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.image = self.create_param(code="image", data_type=DataType.IMAGE, is_required=False) + + +class ImageColorizationOutputs(Outputs): + image: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.image = self.create_param(code="image", data_type=DataType.IMAGE) + + +class ImageColorization(AssetNode[ImageColorizationInputs, ImageColorizationOutputs]): + """ + Image colorization is a process that involves adding color to grayscale images, +transforming them from black-and-white to full-color representations, often +using advanced algorithms and machine learning techniques to predict and apply +the appropriate hues and shades. + + InputType: image + OutputType: image + """ + function: str = "image-colorization" + input_type: str = DataType.IMAGE + output_type: str = DataType.IMAGE + + inputs_class: Type[TI] = ImageColorizationInputs + outputs_class: Type[TO] = ImageColorizationOutputs + + +class AudioGenerationMetricInputs(Inputs): + hypotheses: InputParam = None + references: InputParam = None + sources: InputParam = None + score_identifier: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.hypotheses = self.create_param(code="hypotheses", data_type=DataType.AUDIO, is_required=True) + self.references = self.create_param(code="references", data_type=DataType.AUDIO, is_required=False) + self.sources = self.create_param(code="sources", data_type=DataType.TEXT, is_required=False) + self.score_identifier = self.create_param(code="score_identifier", data_type=DataType.TEXT, is_required=True) + + +class AudioGenerationMetricOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class AudioGenerationMetric(AssetNode[AudioGenerationMetricInputs, AudioGenerationMetricOutputs]): + """ + The Audio Generation Metric is a quantitative measure used to evaluate the +quality, accuracy, and overall performance of audio generated by artificial +intelligence systems, often considering factors such as fidelity, +intelligibility, and similarity to human-produced audio. + + InputType: text + OutputType: text + """ + function: str = "audio-generation-metric" + input_type: str = DataType.TEXT + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = AudioGenerationMetricInputs + outputs_class: Type[TO] = AudioGenerationMetricOutputs + + +class ImageImpaintingInputs(Inputs): + image: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.image = self.create_param(code="image", data_type=DataType.IMAGE, is_required=False) + + +class ImageImpaintingOutputs(Outputs): + image: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.image = self.create_param(code="image", data_type=DataType.IMAGE) + + +class ImageImpainting(AssetNode[ImageImpaintingInputs, ImageImpaintingOutputs]): + """ + Image inpainting is a process that involves filling in missing or damaged parts +of an image in a way that is visually coherent and seamlessly blends with the +surrounding areas, often using advanced algorithms and techniques to restore +the image to its original or intended appearance. + + InputType: image + OutputType: image + """ + function: str = "image-impainting" + input_type: str = DataType.IMAGE + output_type: str = DataType.IMAGE + + inputs_class: Type[TI] = ImageImpaintingInputs + outputs_class: Type[TO] = ImageImpaintingOutputs + + +class StyleTransferInputs(Inputs): + image: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.image = self.create_param(code="image", data_type=DataType.IMAGE, is_required=False) + + +class StyleTransferOutputs(Outputs): + image: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.image = self.create_param(code="image", data_type=DataType.IMAGE) + + +class StyleTransfer(AssetNode[StyleTransferInputs, StyleTransferOutputs]): + """ + Style Transfer is a technique in artificial intelligence that applies the +visual style of one image (such as the brushstrokes of a famous painting) to +the content of another image, effectively blending the artistic elements of the +first image with the subject matter of the second. + + InputType: image + OutputType: image + """ + function: str = "style-transfer" + input_type: str = DataType.IMAGE + output_type: str = DataType.IMAGE + + inputs_class: Type[TI] = StyleTransferInputs + outputs_class: Type[TO] = StyleTransferOutputs + + +class MultiClassTextClassificationInputs(Inputs): + language: InputParam = None + text: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=False) + + +class MultiClassTextClassificationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class MultiClassTextClassification(AssetNode[MultiClassTextClassificationInputs, MultiClassTextClassificationOutputs]): + """ + Multi Class Text Classification is a natural language processing task that +involves categorizing a given text into one of several predefined classes or +categories based on its content. + + InputType: text + OutputType: label + """ + function: str = "multi-class-text-classification" + input_type: str = DataType.TEXT + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = MultiClassTextClassificationInputs + outputs_class: Type[TO] = MultiClassTextClassificationOutputs + + +class TextEmbeddingInputs(Inputs): + text: InputParam = None + language: InputParam = None + dialect: InputParam = None + script: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.dialect = self.create_param(code="dialect", data_type=DataType.LABEL, is_required=False) + self.script = self.create_param(code="script", data_type=DataType.LABEL, is_required=False) + + +class TextEmbeddingOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class TextEmbedding(AssetNode[TextEmbeddingInputs, TextEmbeddingOutputs]): + """ + Text embedding is a process that converts text into numerical vectors, +capturing the semantic meaning and contextual relationships of words or +phrases, enabling machines to understand and analyze natural language more +effectively. + + InputType: text + OutputType: text + """ + function: str = "text-embedding" + input_type: str = DataType.TEXT + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = TextEmbeddingInputs + outputs_class: Type[TO] = TextEmbeddingOutputs + + +class MultiLabelTextClassificationInputs(Inputs): + language: InputParam = None + text: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=False) + + +class MultiLabelTextClassificationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class MultiLabelTextClassification(AssetNode[MultiLabelTextClassificationInputs, MultiLabelTextClassificationOutputs]): + """ + Multi Label Text Classification is a natural language processing task where a +given text is analyzed and assigned multiple relevant labels or categories from +a predefined set, allowing for the text to belong to more than one category +simultaneously. + + InputType: text + OutputType: label + """ + function: str = "multi-label-text-classification" + input_type: str = DataType.TEXT + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = MultiLabelTextClassificationInputs + outputs_class: Type[TO] = MultiLabelTextClassificationOutputs + + +class TextReconstructionInputs(Inputs): + text: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + + +class TextReconstructionOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class TextReconstruction(BaseReconstructor[TextReconstructionInputs, TextReconstructionOutputs]): + """ + Text Reconstruction is a process that involves piecing together fragmented or +incomplete text data to restore it to its original, coherent form. + + InputType: text + OutputType: text + """ + function: str = "text-reconstruction" + input_type: str = DataType.TEXT + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = TextReconstructionInputs + outputs_class: Type[TO] = TextReconstructionOutputs + + +class FactCheckingInputs(Inputs): + language: InputParam = None + text: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=False) + + +class FactCheckingOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class FactChecking(AssetNode[FactCheckingInputs, FactCheckingOutputs]): + """ + Fact Checking is the process of verifying the accuracy and truthfulness of +information, statements, or claims by cross-referencing with reliable sources +and evidence. + + InputType: text + OutputType: label + """ + function: str = "fact-checking" + input_type: str = DataType.TEXT + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = FactCheckingInputs + outputs_class: Type[TO] = FactCheckingOutputs + + +class SpeechClassificationInputs(Inputs): + audio: InputParam = None + language: InputParam = None + script: InputParam = None + dialect: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.audio = self.create_param(code="audio", data_type=DataType.AUDIO, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.script = self.create_param(code="script", data_type=DataType.LABEL, is_required=False) + self.dialect = self.create_param(code="dialect", data_type=DataType.LABEL, is_required=False) + + +class SpeechClassificationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class SpeechClassification(AssetNode[SpeechClassificationInputs, SpeechClassificationOutputs]): + """ + Speech Classification is a process that involves analyzing and categorizing +spoken language into predefined categories or classes based on various features +such as tone, pitch, and linguistic content. + + InputType: audio + OutputType: label + """ + function: str = "speech-classification" + input_type: str = DataType.AUDIO + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = SpeechClassificationInputs + outputs_class: Type[TO] = SpeechClassificationOutputs + + +class IntentClassificationInputs(Inputs): + language: InputParam = None + text: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=False) + + +class IntentClassificationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class IntentClassification(AssetNode[IntentClassificationInputs, IntentClassificationOutputs]): + """ + Intent Classification is a natural language processing task that involves +analyzing and categorizing user text input to determine the underlying purpose +or goal behind the communication, such as booking a flight, asking for weather +information, or setting a reminder. + + InputType: text + OutputType: label + """ + function: str = "intent-classification" + input_type: str = DataType.TEXT + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = IntentClassificationInputs + outputs_class: Type[TO] = IntentClassificationOutputs + + +class PartOfSpeechTaggingInputs(Inputs): + language: InputParam = None + text: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=False) + + +class PartOfSpeechTaggingOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class PartOfSpeechTagging(AssetNode[PartOfSpeechTaggingInputs, PartOfSpeechTaggingOutputs]): + """ + Part of Speech Tagging is a natural language processing task that involves +assigning each word in a sentence its corresponding part of speech, such as +noun, verb, adjective, or adverb, based on its role and context within the +sentence. + + InputType: text + OutputType: label + """ + function: str = "part-of-speech-tagging" + input_type: str = DataType.TEXT + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = PartOfSpeechTaggingInputs + outputs_class: Type[TO] = PartOfSpeechTaggingOutputs + + +class MetricAggregationInputs(Inputs): + text: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + + +class MetricAggregationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class MetricAggregation(AssetNode[MetricAggregationInputs, MetricAggregationOutputs]): + """ + Metric Aggregation is a function that computes and summarizes numerical data by +applying statistical operations, such as averaging, summing, or finding the +minimum and maximum values, to provide insights and facilitate analysis of +large datasets. + + InputType: text + OutputType: text + """ + function: str = "metric-aggregation" + input_type: str = DataType.TEXT + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = MetricAggregationInputs + outputs_class: Type[TO] = MetricAggregationOutputs + + +class DialectDetectionInputs(Inputs): + audio: InputParam = None + language: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.audio = self.create_param(code="audio", data_type=DataType.AUDIO, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=False) + + +class DialectDetectionOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class DialectDetection(AssetNode[DialectDetectionInputs, DialectDetectionOutputs]): + """ + Dialect Detection is a function that identifies and classifies the specific +regional or social variations of a language spoken or written by an individual, +enabling the recognition of distinct linguistic patterns and nuances associated +with different dialects. + + InputType: audio + OutputType: text + """ + function: str = "dialect-detection" + input_type: str = DataType.AUDIO + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = DialectDetectionInputs + outputs_class: Type[TO] = DialectDetectionOutputs + + +class InverseTextNormalizationInputs(Inputs): + text: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=False) + + +class InverseTextNormalizationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class InverseTextNormalization(AssetNode[InverseTextNormalizationInputs, InverseTextNormalizationOutputs]): + """ + Inverse Text Normalization is the process of converting spoken or written +language in its normalized form, such as numbers, dates, and abbreviations, +back into their original, more complex or detailed textual representations. + + InputType: text + OutputType: label + """ + function: str = "inverse-text-normalization" + input_type: str = DataType.TEXT + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = InverseTextNormalizationInputs + outputs_class: Type[TO] = InverseTextNormalizationOutputs + + +class TextToAudioInputs(Inputs): + text: InputParam = None + language: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=False) + + +class TextToAudioOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.AUDIO) + + +class TextToAudio(AssetNode[TextToAudioInputs, TextToAudioOutputs]): + """ + The Text to Audio function converts written text into spoken words, allowing +users to listen to the content instead of reading it. + + InputType: text + OutputType: audio + """ + function: str = "text-to-audio" + input_type: str = DataType.TEXT + output_type: str = DataType.AUDIO + + inputs_class: Type[TI] = TextToAudioInputs + outputs_class: Type[TO] = TextToAudioOutputs + + +class FillTextMaskInputs(Inputs): + text: InputParam = None + language: InputParam = None + dialect: InputParam = None + script: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.dialect = self.create_param(code="dialect", data_type=DataType.LABEL, is_required=False) + self.script = self.create_param(code="script", data_type=DataType.LABEL, is_required=False) + + +class FillTextMaskOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class FillTextMask(AssetNode[FillTextMaskInputs, FillTextMaskOutputs]): + """ + The "Fill Text Mask" function takes a text input with masked or placeholder +characters and replaces those placeholders with specified or contextually +appropriate characters to generate a complete and coherent text output. + + InputType: text + OutputType: text + """ + function: str = "fill-text-mask" + input_type: str = DataType.TEXT + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = FillTextMaskInputs + outputs_class: Type[TO] = FillTextMaskOutputs + + +class VideoContentModerationInputs(Inputs): + video: InputParam = None + min_confidence: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.video = self.create_param(code="video", data_type=DataType.VIDEO, is_required=True) + self.min_confidence = self.create_param(code="min_confidence", data_type=DataType.TEXT, is_required=False) + + +class VideoContentModerationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class VideoContentModeration(AssetNode[VideoContentModerationInputs, VideoContentModerationOutputs]): + """ + Video Content Moderation is the process of reviewing, analyzing, and filtering +video content to ensure it adheres to community guidelines, legal standards, +and platform policies, thereby preventing the dissemination of inappropriate, +harmful, or illegal material. + + InputType: video + OutputType: label + """ + function: str = "video-content-moderation" + input_type: str = DataType.VIDEO + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = VideoContentModerationInputs + outputs_class: Type[TO] = VideoContentModerationOutputs + + +class ExtractAudioFromVideoInputs(Inputs): + video: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.video = self.create_param(code="video", data_type=DataType.VIDEO, is_required=True) + + +class ExtractAudioFromVideoOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.AUDIO) + + +class ExtractAudioFromVideo(AssetNode[ExtractAudioFromVideoInputs, ExtractAudioFromVideoOutputs]): + """ + The "Extract Audio From Video" function allows users to separate and save the +audio track from a video file, enabling them to obtain just the sound without +the accompanying visual content. + + InputType: video + OutputType: audio + """ + function: str = "extract-audio-from-video" + input_type: str = DataType.VIDEO + output_type: str = DataType.AUDIO + + inputs_class: Type[TI] = ExtractAudioFromVideoInputs + outputs_class: Type[TO] = ExtractAudioFromVideoOutputs + + +class ImageCompressionInputs(Inputs): + image: InputParam = None + apl_qfactor: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.image = self.create_param(code="image", data_type=DataType.IMAGE, is_required=True) + self.apl_qfactor = self.create_param(code="apl_qfactor", data_type=DataType.TEXT, is_required=False) + + +class ImageCompressionOutputs(Outputs): + image: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.image = self.create_param(code="image", data_type=DataType.IMAGE) + + +class ImageCompression(AssetNode[ImageCompressionInputs, ImageCompressionOutputs]): + """ + Image compression is a process that reduces the file size of an image by +removing redundant or non-essential data, while maintaining an acceptable level +of visual quality. + + InputType: image + OutputType: image + """ + function: str = "image-compression" + input_type: str = DataType.IMAGE + output_type: str = DataType.IMAGE + + inputs_class: Type[TI] = ImageCompressionInputs + outputs_class: Type[TO] = ImageCompressionOutputs + + +class MultilingualSpeechRecognitionInputs(Inputs): + source_audio: InputParam = None + language: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.source_audio = self.create_param(code="source_audio", data_type=DataType.AUDIO, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=False) + + +class MultilingualSpeechRecognitionOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class MultilingualSpeechRecognition(AssetNode[MultilingualSpeechRecognitionInputs, MultilingualSpeechRecognitionOutputs]): + """ + Multilingual Speech Recognition is a technology that enables the automatic +transcription of spoken language into text across multiple languages, allowing +for seamless communication and understanding in diverse linguistic contexts. + + InputType: audio + OutputType: text + """ + function: str = "multilingual-speech-recognition" + input_type: str = DataType.AUDIO + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = MultilingualSpeechRecognitionInputs + outputs_class: Type[TO] = MultilingualSpeechRecognitionOutputs + + +class ReferencelessTextGenerationMetricInputs(Inputs): + hypotheses: InputParam = None + sources: InputParam = None + score_identifier: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.hypotheses = self.create_param(code="hypotheses", data_type=DataType.TEXT, is_required=True) + self.sources = self.create_param(code="sources", data_type=DataType.TEXT, is_required=False) + self.score_identifier = self.create_param(code="score_identifier", data_type=DataType.TEXT, is_required=True) + + +class ReferencelessTextGenerationMetricOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class ReferencelessTextGenerationMetric(AssetNode[ReferencelessTextGenerationMetricInputs, ReferencelessTextGenerationMetricOutputs]): + """ + The Referenceless Text Generation Metric is a method for evaluating the quality +of generated text without requiring a reference text for comparison, often +leveraging models or algorithms to assess coherence, relevance, and fluency +based on intrinsic properties of the text itself. + + InputType: text + OutputType: text + """ + function: str = "referenceless-text-generation-metric" + input_type: str = DataType.TEXT + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = ReferencelessTextGenerationMetricInputs + outputs_class: Type[TO] = ReferencelessTextGenerationMetricOutputs + + +class TextGenerationMetricDefaultInputs(Inputs): + hypotheses: InputParam = None + references: InputParam = None + sources: InputParam = None + score_identifier: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.hypotheses = self.create_param(code="hypotheses", data_type=DataType.TEXT, is_required=True) + self.references = self.create_param(code="references", data_type=DataType.TEXT, is_required=False) + self.sources = self.create_param(code="sources", data_type=DataType.TEXT, is_required=False) + self.score_identifier = self.create_param(code="score_identifier", data_type=DataType.TEXT, is_required=True) + + +class TextGenerationMetricDefaultOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class TextGenerationMetricDefault(AssetNode[TextGenerationMetricDefaultInputs, TextGenerationMetricDefaultOutputs]): + """ + The "Text Generation Metric Default" function provides a standard set of +evaluation metrics for assessing the quality and performance of text generation +models. + + InputType: text + OutputType: text + """ + function: str = "text-generation-metric-default" + input_type: str = DataType.TEXT + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = TextGenerationMetricDefaultInputs + outputs_class: Type[TO] = TextGenerationMetricDefaultOutputs + + +class NoiseRemovalInputs(Inputs): + audio: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.audio = self.create_param(code="audio", data_type=DataType.AUDIO, is_required=False) + + +class NoiseRemovalOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.AUDIO) + + +class NoiseRemoval(AssetNode[NoiseRemovalInputs, NoiseRemovalOutputs]): + """ + Noise Removal is a process that involves identifying and eliminating unwanted +random variations or disturbances from an audio signal to enhance the clarity +and quality of the underlying information. + + InputType: audio + OutputType: audio + """ + function: str = "noise-removal" + input_type: str = DataType.AUDIO + output_type: str = DataType.AUDIO + + inputs_class: Type[TI] = NoiseRemovalInputs + outputs_class: Type[TO] = NoiseRemovalOutputs + + +class AudioReconstructionInputs(Inputs): + audio: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.audio = self.create_param(code="audio", data_type=DataType.AUDIO, is_required=True) + + +class AudioReconstructionOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.AUDIO) + + +class AudioReconstruction(BaseReconstructor[AudioReconstructionInputs, AudioReconstructionOutputs]): + """ + Audio Reconstruction is the process of restoring or recreating audio signals +from incomplete, damaged, or degraded recordings to achieve a high-quality, +accurate representation of the original sound. + + InputType: audio + OutputType: audio + """ + function: str = "audio-reconstruction" + input_type: str = DataType.AUDIO + output_type: str = DataType.AUDIO + + inputs_class: Type[TI] = AudioReconstructionInputs + outputs_class: Type[TO] = AudioReconstructionOutputs + + +class VoiceCloningInputs(Inputs): + text: InputParam = None + audio: InputParam = None + language: InputParam = None + dialect: InputParam = None + voice: InputParam = None + script: InputParam = None + type: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.audio = self.create_param(code="audio", data_type=DataType.AUDIO, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.dialect = self.create_param(code="dialect", data_type=DataType.LABEL, is_required=False) + self.voice = self.create_param(code="voice", data_type=DataType.LABEL, is_required=False) + self.script = self.create_param(code="script", data_type=DataType.LABEL, is_required=False) + self.type = self.create_param(code="type", data_type=DataType.LABEL, is_required=False) + + +class VoiceCloningOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.AUDIO) + + +class VoiceCloning(AssetNode[VoiceCloningInputs, VoiceCloningOutputs]): + """ + Voice cloning is a technology that uses artificial intelligence to create a +digital replica of a person's voice, allowing for the generation of speech that +mimics the tone, pitch, and speaking style of the original speaker. + + InputType: text + OutputType: audio + """ + function: str = "voice-cloning" + input_type: str = DataType.TEXT + output_type: str = DataType.AUDIO + + inputs_class: Type[TI] = VoiceCloningInputs + outputs_class: Type[TO] = VoiceCloningOutputs + + +class DiacritizationInputs(Inputs): + language: InputParam = None + dialect: InputParam = None + script: InputParam = None + text: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.dialect = self.create_param(code="dialect", data_type=DataType.LABEL, is_required=True) + self.script = self.create_param(code="script", data_type=DataType.LABEL, is_required=False) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + + +class DiacritizationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class Diacritization(AssetNode[DiacritizationInputs, DiacritizationOutputs]): + """ + Diacritization is the process of adding diacritical marks to letters in a text +to indicate pronunciation, stress, tone, or meaning, often used in languages +such as Arabic, Hebrew, and Vietnamese to provide clarity and accuracy in +written communication. + + InputType: text + OutputType: text + """ + function: str = "diacritization" + input_type: str = DataType.TEXT + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = DiacritizationInputs + outputs_class: Type[TO] = DiacritizationOutputs + + +class AudioEmotionDetectionInputs(Inputs): + audio: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.audio = self.create_param(code="audio", data_type=DataType.AUDIO, is_required=False) + + +class AudioEmotionDetectionOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class AudioEmotionDetection(AssetNode[AudioEmotionDetectionInputs, AudioEmotionDetectionOutputs]): + """ + Audio Emotion Detection is a technology that analyzes vocal characteristics and +patterns in audio recordings to identify and classify the emotional state of +the speaker. + + InputType: audio + OutputType: label + """ + function: str = "audio-emotion-detection" + input_type: str = DataType.AUDIO + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = AudioEmotionDetectionInputs + outputs_class: Type[TO] = AudioEmotionDetectionOutputs + + +class TextSummarizationInputs(Inputs): + text: InputParam = None + language: InputParam = None + script: InputParam = None + dialect: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.script = self.create_param(code="script", data_type=DataType.LABEL, is_required=False) + self.dialect = self.create_param(code="dialect", data_type=DataType.LABEL, is_required=False) + + +class TextSummarizationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class TextSummarization(AssetNode[TextSummarizationInputs, TextSummarizationOutputs]): + """ + Text summarization is the process of condensing a large body of text into a +shorter version, capturing the main points and essential information while +maintaining coherence and meaning. + + InputType: text + OutputType: text + """ + function: str = "text-summarization" + input_type: str = DataType.TEXT + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = TextSummarizationInputs + outputs_class: Type[TO] = TextSummarizationOutputs + + +class EntityLinkingInputs(Inputs): + text: InputParam = None + language: InputParam = None + domain: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.domain = self.create_param(code="domain", data_type=DataType.LABEL, is_required=False) + + +class EntityLinkingOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class EntityLinking(AssetNode[EntityLinkingInputs, EntityLinkingOutputs]): + """ + Entity Linking is the process of identifying and connecting mentions of +entities within a text to their corresponding entries in a structured knowledge +base, thereby enabling the disambiguation of terms and enhancing the +understanding of the text's context. + + InputType: text + OutputType: label + """ + function: str = "entity-linking" + input_type: str = DataType.TEXT + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = EntityLinkingInputs + outputs_class: Type[TO] = EntityLinkingOutputs + + +class TextGenerationMetricInputs(Inputs): + hypotheses: InputParam = None + references: InputParam = None + sources: InputParam = None + score_identifier: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.hypotheses = self.create_param(code="hypotheses", data_type=DataType.TEXT, is_required=True) + self.references = self.create_param(code="references", data_type=DataType.TEXT, is_required=False) + self.sources = self.create_param(code="sources", data_type=DataType.TEXT, is_required=False) + self.score_identifier = self.create_param(code="score_identifier", data_type=DataType.TEXT, is_required=True) + + +class TextGenerationMetricOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class TextGenerationMetric(AssetNode[TextGenerationMetricInputs, TextGenerationMetricOutputs]): + """ + A Text Generation Metric is a quantitative measure used to evaluate the quality +and effectiveness of text produced by natural language processing models, often +assessing aspects such as coherence, relevance, fluency, and adherence to given +prompts or instructions. + + InputType: text + OutputType: text + """ + function: str = "text-generation-metric" + input_type: str = DataType.TEXT + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = TextGenerationMetricInputs + outputs_class: Type[TO] = TextGenerationMetricOutputs + + +class SplitOnLinebreakInputs(Inputs): + text: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + + +class SplitOnLinebreakOutputs(Outputs): + data: OutputParam = None + audio: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + self.audio = self.create_param(code="audio", data_type=DataType.AUDIO) + + +class SplitOnLinebreak(BaseSegmentor[SplitOnLinebreakInputs, SplitOnLinebreakOutputs]): + """ + The "Split On Linebreak" function divides a given string into a list of +substrings, using linebreaks (newline characters) as the points of separation. + + InputType: text + OutputType: text + """ + function: str = "split-on-linebreak" + input_type: str = DataType.TEXT + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = SplitOnLinebreakInputs + outputs_class: Type[TO] = SplitOnLinebreakOutputs + + +class SentimentAnalysisInputs(Inputs): + text: InputParam = None + language: InputParam = None + dialect: InputParam = None + script: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.dialect = self.create_param(code="dialect", data_type=DataType.LABEL, is_required=False) + self.script = self.create_param(code="script", data_type=DataType.LABEL, is_required=False) + + +class SentimentAnalysisOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class SentimentAnalysis(AssetNode[SentimentAnalysisInputs, SentimentAnalysisOutputs]): + """ + Sentiment Analysis is a natural language processing technique used to determine +and classify the emotional tone or subjective information expressed in a piece +of text, such as identifying whether the sentiment is positive, negative, or +neutral. + + InputType: text + OutputType: label + """ + function: str = "sentiment-analysis" + input_type: str = DataType.TEXT + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = SentimentAnalysisInputs + outputs_class: Type[TO] = SentimentAnalysisOutputs + + +class KeywordSpottingInputs(Inputs): + audio: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.audio = self.create_param(code="audio", data_type=DataType.AUDIO, is_required=False) + + +class KeywordSpottingOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class KeywordSpotting(AssetNode[KeywordSpottingInputs, KeywordSpottingOutputs]): + """ + Keyword Spotting is a function that enables the detection and identification of +specific words or phrases within a stream of audio, often used in voice- +activated systems to trigger actions or commands based on recognized keywords. + + InputType: audio + OutputType: label + """ + function: str = "keyword-spotting" + input_type: str = DataType.AUDIO + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = KeywordSpottingInputs + outputs_class: Type[TO] = KeywordSpottingOutputs + + +class TextClassificationInputs(Inputs): + text: InputParam = None + language: InputParam = None + dialect: InputParam = None + script: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.dialect = self.create_param(code="dialect", data_type=DataType.LABEL, is_required=False) + self.script = self.create_param(code="script", data_type=DataType.LABEL, is_required=False) + + +class TextClassificationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class TextClassification(AssetNode[TextClassificationInputs, TextClassificationOutputs]): + """ + Text Classification is a natural language processing task that involves +categorizing text into predefined labels or classes based on its content, +enabling automated organization, filtering, and analysis of large volumes of +textual data. + + InputType: text + OutputType: label + """ + function: str = "text-classification" + input_type: str = DataType.TEXT + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = TextClassificationInputs + outputs_class: Type[TO] = TextClassificationOutputs + + +class OtherMultipurposeInputs(Inputs): + text: InputParam = None + language: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + + +class OtherMultipurposeOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class OtherMultipurpose(AssetNode[OtherMultipurposeInputs, OtherMultipurposeOutputs]): + """ + The "Other (Multipurpose)" function serves as a versatile category designed to +accommodate a wide range of tasks and activities that do not fit neatly into +predefined classifications, offering flexibility and adaptability for various +needs. + + InputType: text + OutputType: text + """ + function: str = "other-(multipurpose)" + input_type: str = DataType.TEXT + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = OtherMultipurposeInputs + outputs_class: Type[TO] = OtherMultipurposeOutputs + + +class SpeechSynthesisInputs(Inputs): + audio: InputParam = None + language: InputParam = None + dialect: InputParam = None + voice: InputParam = None + script: InputParam = None + text: InputParam = None + type: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.audio = self.create_param(code="audio", data_type=DataType.AUDIO, is_required=False) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.dialect = self.create_param(code="dialect", data_type=DataType.LABEL, is_required=False) + self.voice = self.create_param(code="voice", data_type=DataType.LABEL, is_required=False) + self.script = self.create_param(code="script", data_type=DataType.LABEL, is_required=False) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.type = self.create_param(code="type", data_type=DataType.LABEL, is_required=False) + + +class SpeechSynthesisOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.AUDIO) + + +class SpeechSynthesis(AssetNode[SpeechSynthesisInputs, SpeechSynthesisOutputs]): + """ + Speech synthesis is the artificial production of human speech, typically +achieved through software or hardware systems that convert text into spoken +words, enabling machines to communicate verbally with users. + + InputType: text + OutputType: audio + """ + function: str = "speech-synthesis" + input_type: str = DataType.TEXT + output_type: str = DataType.AUDIO + + inputs_class: Type[TI] = SpeechSynthesisInputs + outputs_class: Type[TO] = SpeechSynthesisOutputs + + +class AudioIntentDetectionInputs(Inputs): + audio: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.audio = self.create_param(code="audio", data_type=DataType.AUDIO, is_required=False) + + +class AudioIntentDetectionOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class AudioIntentDetection(AssetNode[AudioIntentDetectionInputs, AudioIntentDetectionOutputs]): + """ + Audio Intent Detection is a process that involves analyzing audio signals to +identify and interpret the underlying intentions or purposes behind spoken +words, enabling systems to understand and respond appropriately to human +speech. + + InputType: audio + OutputType: label + """ + function: str = "audio-intent-detection" + input_type: str = DataType.AUDIO + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = AudioIntentDetectionInputs + outputs_class: Type[TO] = AudioIntentDetectionOutputs + + +class VideoLabelDetectionInputs(Inputs): + video: InputParam = None + min_confidence: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.video = self.create_param(code="video", data_type=DataType.VIDEO, is_required=True) + self.min_confidence = self.create_param(code="min_confidence", data_type=DataType.TEXT, is_required=False) + + +class VideoLabelDetectionOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class VideoLabelDetection(AssetNode[VideoLabelDetectionInputs, VideoLabelDetectionOutputs]): + """ + Video Label Detection is a function that automatically identifies and tags +various objects, scenes, activities, and other relevant elements within a +video, providing descriptive labels that enhance searchability and content +organization. + + InputType: video + OutputType: label + """ + function: str = "video-label-detection" + input_type: str = DataType.VIDEO + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = VideoLabelDetectionInputs + outputs_class: Type[TO] = VideoLabelDetectionOutputs + + +class AsrQualityEstimationInputs(Inputs): + text: InputParam = None + script: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.script = self.create_param(code="script", data_type=DataType.LABEL, is_required=False) + + +class AsrQualityEstimationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class AsrQualityEstimation(AssetNode[AsrQualityEstimationInputs, AsrQualityEstimationOutputs]): + """ + ASR Quality Estimation is a process that evaluates the accuracy and reliability +of automatic speech recognition systems by analyzing their performance in +transcribing spoken language into text. + + InputType: text + OutputType: label + """ + function: str = "asr-quality-estimation" + input_type: str = DataType.TEXT + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = AsrQualityEstimationInputs + outputs_class: Type[TO] = AsrQualityEstimationOutputs + + +class AudioTranscriptAnalysisInputs(Inputs): + language: InputParam = None + dialect: InputParam = None + source_supplier: InputParam = None + source_audio: InputParam = None + script: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.dialect = self.create_param(code="dialect", data_type=DataType.LABEL, is_required=False) + self.source_supplier = self.create_param(code="source_supplier", data_type=DataType.LABEL, is_required=False) + self.source_audio = self.create_param(code="source_audio", data_type=DataType.AUDIO, is_required=True) + self.script = self.create_param(code="script", data_type=DataType.LABEL, is_required=False) + + +class AudioTranscriptAnalysisOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class AudioTranscriptAnalysis(AssetNode[AudioTranscriptAnalysisInputs, AudioTranscriptAnalysisOutputs]): + """ + Audio Transcript Analysis is a process that involves converting spoken language +from audio recordings into written text, followed by examining and interpreting +the transcribed content to extract meaningful insights, identify patterns, and +derive actionable information. + + InputType: audio + OutputType: text + """ + function: str = "audio-transcript-analysis" + input_type: str = DataType.AUDIO + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = AudioTranscriptAnalysisInputs + outputs_class: Type[TO] = AudioTranscriptAnalysisOutputs + + +class SearchInputs(Inputs): + text: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + + +class SearchOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class Search(AssetNode[SearchInputs, SearchOutputs]): + """ + The "Search" function allows users to input keywords or phrases to quickly +locate specific information, files, or content within a database, website, or +application. + + InputType: text + OutputType: text + """ + function: str = "search" + input_type: str = DataType.TEXT + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = SearchInputs + outputs_class: Type[TO] = SearchOutputs + + +class VideoForcedAlignmentInputs(Inputs): + video: InputParam = None + text: InputParam = None + language: InputParam = None + dialect: InputParam = None + script: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.video = self.create_param(code="video", data_type=DataType.VIDEO, is_required=True) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.dialect = self.create_param(code="dialect", data_type=DataType.LABEL, is_required=False) + self.script = self.create_param(code="script", data_type=DataType.LABEL, is_required=False) + + +class VideoForcedAlignmentOutputs(Outputs): + text: OutputParam = None + video: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT) + self.video = self.create_param(code="video", data_type=DataType.VIDEO) + + +class VideoForcedAlignment(AssetNode[VideoForcedAlignmentInputs, VideoForcedAlignmentOutputs]): + """ + Video Forced Alignment is a process that synchronizes video footage with +corresponding audio tracks by precisely aligning the visual and auditory +elements, ensuring that the movements of speakers' lips match the spoken words. + + InputType: video + OutputType: video + """ + function: str = "video-forced-alignment" + input_type: str = DataType.VIDEO + output_type: str = DataType.VIDEO + + inputs_class: Type[TI] = VideoForcedAlignmentInputs + outputs_class: Type[TO] = VideoForcedAlignmentOutputs + + +class VisemeGenerationInputs(Inputs): + text: InputParam = None + language: InputParam = None + dialect: InputParam = None + script: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.dialect = self.create_param(code="dialect", data_type=DataType.LABEL, is_required=False) + self.script = self.create_param(code="script", data_type=DataType.LABEL, is_required=False) + + +class VisemeGenerationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class VisemeGeneration(AssetNode[VisemeGenerationInputs, VisemeGenerationOutputs]): + """ + Viseme Generation is the process of creating visual representations of +phonemes, which are the distinct units of sound in speech, to synchronize lip +movements with spoken words in animations or virtual avatars. + + InputType: text + OutputType: label + """ + function: str = "viseme-generation" + input_type: str = DataType.TEXT + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = VisemeGenerationInputs + outputs_class: Type[TO] = VisemeGenerationOutputs + + +class TopicClassificationInputs(Inputs): + text: InputParam = None + language: InputParam = None + script: InputParam = None + dialect: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.script = self.create_param(code="script", data_type=DataType.LABEL, is_required=False) + self.dialect = self.create_param(code="dialect", data_type=DataType.LABEL, is_required=False) + + +class TopicClassificationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class TopicClassification(AssetNode[TopicClassificationInputs, TopicClassificationOutputs]): + """ + Topic Classification is a natural language processing function that categorizes +text into predefined topics or subjects based on its content, enabling +efficient organization and retrieval of information. + + InputType: text + OutputType: label + """ + function: str = "topic-classification" + input_type: str = DataType.TEXT + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = TopicClassificationInputs + outputs_class: Type[TO] = TopicClassificationOutputs + + +class OffensiveLanguageIdentificationInputs(Inputs): + text: InputParam = None + language: InputParam = None + dialect: InputParam = None + script: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.dialect = self.create_param(code="dialect", data_type=DataType.LABEL, is_required=False) + self.script = self.create_param(code="script", data_type=DataType.LABEL, is_required=False) + + +class OffensiveLanguageIdentificationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class OffensiveLanguageIdentification(AssetNode[OffensiveLanguageIdentificationInputs, OffensiveLanguageIdentificationOutputs]): + """ + Offensive Language Identification is a function that analyzes text to detect +and flag language that is abusive, harmful, or inappropriate, helping to +maintain a respectful and safe communication environment. + + InputType: text + OutputType: label + """ + function: str = "offensive-language-identification" + input_type: str = DataType.TEXT + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = OffensiveLanguageIdentificationInputs + outputs_class: Type[TO] = OffensiveLanguageIdentificationOutputs + + +class SpeechTranslationInputs(Inputs): + source_audio: InputParam = None + sourcelanguage: InputParam = None + targetlanguage: InputParam = None + dialect: InputParam = None + voice: InputParam = None + script: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.source_audio = self.create_param(code="source_audio", data_type=DataType.AUDIO, is_required=True) + self.sourcelanguage = self.create_param(code="sourcelanguage", data_type=DataType.LABEL, is_required=True) + self.targetlanguage = self.create_param(code="targetlanguage", data_type=DataType.LABEL, is_required=True) + self.dialect = self.create_param(code="dialect", data_type=DataType.LABEL, is_required=False) + self.voice = self.create_param(code="voice", data_type=DataType.LABEL, is_required=False) + self.script = self.create_param(code="script", data_type=DataType.LABEL, is_required=False) + + +class SpeechTranslationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class SpeechTranslation(AssetNode[SpeechTranslationInputs, SpeechTranslationOutputs]): + """ + Speech Translation is a technology that converts spoken language in real-time +from one language to another, enabling seamless communication between speakers +of different languages. + + InputType: audio + OutputType: text + """ + function: str = "speech-translation" + input_type: str = DataType.AUDIO + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = SpeechTranslationInputs + outputs_class: Type[TO] = SpeechTranslationOutputs + + +class SpeakerDiarizationAudioInputs(Inputs): + audio: InputParam = None + language: InputParam = None + script: InputParam = None + dialect: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.audio = self.create_param(code="audio", data_type=DataType.AUDIO, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=False) + self.script = self.create_param(code="script", data_type=DataType.LABEL, is_required=False) + self.dialect = self.create_param(code="dialect", data_type=DataType.LABEL, is_required=False) + + +class SpeakerDiarizationAudioOutputs(Outputs): + data: OutputParam = None + audio: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + self.audio = self.create_param(code="audio", data_type=DataType.AUDIO) + + +class SpeakerDiarizationAudio(BaseSegmentor[SpeakerDiarizationAudioInputs, SpeakerDiarizationAudioOutputs]): + """ + Speaker Diarization Audio is a process that involves segmenting an audio +recording into distinct sections, each corresponding to a different speaker, in +order to identify and differentiate between multiple speakers within the same +audio stream. + + InputType: audio + OutputType: label + """ + function: str = "speaker-diarization-audio" + input_type: str = DataType.AUDIO + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = SpeakerDiarizationAudioInputs + outputs_class: Type[TO] = SpeakerDiarizationAudioOutputs + + +class AudioTranscriptImprovementInputs(Inputs): + language: InputParam = None + dialect: InputParam = None + source_supplier: InputParam = None + is_medical: InputParam = None + source_audio: InputParam = None + script: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.dialect = self.create_param(code="dialect", data_type=DataType.LABEL, is_required=False) + self.source_supplier = self.create_param(code="source_supplier", data_type=DataType.LABEL, is_required=False) + self.is_medical = self.create_param(code="is_medical", data_type=DataType.TEXT, is_required=True) + self.source_audio = self.create_param(code="source_audio", data_type=DataType.AUDIO, is_required=True) + self.script = self.create_param(code="script", data_type=DataType.LABEL, is_required=False) + + +class AudioTranscriptImprovementOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class AudioTranscriptImprovement(AssetNode[AudioTranscriptImprovementInputs, AudioTranscriptImprovementOutputs]): + """ + Audio Transcript Improvement is a function that enhances the accuracy and +clarity of transcribed audio recordings by correcting errors, refining +language, and ensuring the text faithfully represents the original spoken +content. + + InputType: audio + OutputType: text + """ + function: str = "audio-transcript-improvement" + input_type: str = DataType.AUDIO + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = AudioTranscriptImprovementInputs + outputs_class: Type[TO] = AudioTranscriptImprovementOutputs + + +class SpeechNonSpeechClassificationInputs(Inputs): + audio: InputParam = None + language: InputParam = None + script: InputParam = None + dialect: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.audio = self.create_param(code="audio", data_type=DataType.AUDIO, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.script = self.create_param(code="script", data_type=DataType.LABEL, is_required=False) + self.dialect = self.create_param(code="dialect", data_type=DataType.LABEL, is_required=False) + + +class SpeechNonSpeechClassificationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class SpeechNonSpeechClassification(AssetNode[SpeechNonSpeechClassificationInputs, SpeechNonSpeechClassificationOutputs]): + """ + The function "Speech or Non-Speech Classification" is designed to analyze audio +input and determine whether the sound is human speech or non-speech noise, +enabling applications such as voice recognition systems to filter out +irrelevant background sounds. + + InputType: audio + OutputType: label + """ + function: str = "speech-non-speech-classification" + input_type: str = DataType.AUDIO + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = SpeechNonSpeechClassificationInputs + outputs_class: Type[TO] = SpeechNonSpeechClassificationOutputs + + +class TextDenormalizationInputs(Inputs): + text: InputParam = None + language: InputParam = None + lowercase_latin: InputParam = None + remove_accents: InputParam = None + remove_punctuation: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.lowercase_latin = self.create_param(code="lowercase_latin", data_type=DataType.TEXT, is_required=False) + self.remove_accents = self.create_param(code="remove_accents", data_type=DataType.TEXT, is_required=False) + self.remove_punctuation = self.create_param(code="remove_punctuation", data_type=DataType.TEXT, is_required=False) + + +class TextDenormalizationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class TextDenormalization(AssetNode[TextDenormalizationInputs, TextDenormalizationOutputs]): + """ + Text Denormalization is the process of converting abbreviated, contracted, or +otherwise simplified text into its full, standard form, often to improve +readability and ensure consistency in natural language processing tasks. + + InputType: text + OutputType: label + """ + function: str = "text-denormalization" + input_type: str = DataType.TEXT + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = TextDenormalizationInputs + outputs_class: Type[TO] = TextDenormalizationOutputs + + +class ImageContentModerationInputs(Inputs): + image: InputParam = None + min_confidence: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.image = self.create_param(code="image", data_type=DataType.IMAGE, is_required=True) + self.min_confidence = self.create_param(code="min_confidence", data_type=DataType.TEXT, is_required=False) + + +class ImageContentModerationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class ImageContentModeration(AssetNode[ImageContentModerationInputs, ImageContentModerationOutputs]): + """ + Image Content Moderation is a process that involves analyzing and filtering +images to detect and manage inappropriate, harmful, or sensitive content, +ensuring compliance with community guidelines and legal standards. + + InputType: image + OutputType: label + """ + function: str = "image-content-moderation" + input_type: str = DataType.IMAGE + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = ImageContentModerationInputs + outputs_class: Type[TO] = ImageContentModerationOutputs + + +class ReferencelessTextGenerationMetricDefaultInputs(Inputs): + hypotheses: InputParam = None + sources: InputParam = None + score_identifier: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.hypotheses = self.create_param(code="hypotheses", data_type=DataType.TEXT, is_required=True) + self.sources = self.create_param(code="sources", data_type=DataType.TEXT, is_required=False) + self.score_identifier = self.create_param(code="score_identifier", data_type=DataType.TEXT, is_required=True) + + +class ReferencelessTextGenerationMetricDefaultOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class ReferencelessTextGenerationMetricDefault(AssetNode[ReferencelessTextGenerationMetricDefaultInputs, ReferencelessTextGenerationMetricDefaultOutputs]): + """ + The Referenceless Text Generation Metric Default is a function designed to +evaluate the quality of generated text without relying on reference texts for +comparison. + + InputType: text + OutputType: text + """ + function: str = "referenceless-text-generation-metric-default" + input_type: str = DataType.TEXT + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = ReferencelessTextGenerationMetricDefaultInputs + outputs_class: Type[TO] = ReferencelessTextGenerationMetricDefaultOutputs + + +class NamedEntityRecognitionInputs(Inputs): + text: InputParam = None + language: InputParam = None + dialect: InputParam = None + script: InputParam = None + domain: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.dialect = self.create_param(code="dialect", data_type=DataType.LABEL, is_required=False) + self.script = self.create_param(code="script", data_type=DataType.LABEL, is_required=False) + self.domain = self.create_param(code="domain", data_type=DataType.LABEL, is_required=False) + + +class NamedEntityRecognitionOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class NamedEntityRecognition(AssetNode[NamedEntityRecognitionInputs, NamedEntityRecognitionOutputs]): + """ + Named Entity Recognition (NER) is a natural language processing task that +involves identifying and classifying proper nouns in text into predefined +categories such as names of people, organizations, locations, dates, and other +entities. + + InputType: text + OutputType: label + """ + function: str = "named-entity-recognition" + input_type: str = DataType.TEXT + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = NamedEntityRecognitionInputs + outputs_class: Type[TO] = NamedEntityRecognitionOutputs + + +class TextContentModerationInputs(Inputs): + text: InputParam = None + language: InputParam = None + dialect: InputParam = None + script: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.dialect = self.create_param(code="dialect", data_type=DataType.LABEL, is_required=False) + self.script = self.create_param(code="script", data_type=DataType.LABEL, is_required=False) + + +class TextContentModerationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class TextContentModeration(AssetNode[TextContentModerationInputs, TextContentModerationOutputs]): + """ + Text Content Moderation is the process of reviewing, filtering, and managing +user-generated content to ensure it adheres to community guidelines, legal +standards, and platform policies, thereby maintaining a safe and respectful +online environment. + + InputType: text + OutputType: label + """ + function: str = "text-content-moderation" + input_type: str = DataType.TEXT + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = TextContentModerationInputs + outputs_class: Type[TO] = TextContentModerationOutputs + + +class SpeakerDiarizationVideoInputs(Inputs): + video: InputParam = None + language: InputParam = None + script: InputParam = None + dialect: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.video = self.create_param(code="video", data_type=DataType.VIDEO, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=False) + self.script = self.create_param(code="script", data_type=DataType.LABEL, is_required=False) + self.dialect = self.create_param(code="dialect", data_type=DataType.LABEL, is_required=False) + + +class SpeakerDiarizationVideoOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.VIDEO) + + +class SpeakerDiarizationVideo(AssetNode[SpeakerDiarizationVideoInputs, SpeakerDiarizationVideoOutputs]): + """ + The Speaker Diarization Video function identifies and segments different +speakers in a video, attributing portions of the audio to individual speakers +to facilitate analysis and understanding of multi-speaker conversations. + + InputType: video + OutputType: label + """ + function: str = "speaker-diarization-video" + input_type: str = DataType.VIDEO + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = SpeakerDiarizationVideoInputs + outputs_class: Type[TO] = SpeakerDiarizationVideoOutputs + + +class SplitOnSilenceInputs(Inputs): + audio: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.audio = self.create_param(code="audio", data_type=DataType.AUDIO, is_required=True) + + +class SplitOnSilenceOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.AUDIO) + + +class SplitOnSilence(AssetNode[SplitOnSilenceInputs, SplitOnSilenceOutputs]): + """ + The "Split On Silence" function divides an audio recording into separate +segments based on periods of silence, allowing for easier editing and analysis +of individual sections. + + InputType: audio + OutputType: audio + """ + function: str = "split-on-silence" + input_type: str = DataType.AUDIO + output_type: str = DataType.AUDIO + + inputs_class: Type[TI] = SplitOnSilenceInputs + outputs_class: Type[TO] = SplitOnSilenceOutputs + + +class EmotionDetectionInputs(Inputs): + text: InputParam = None + language: InputParam = None + dialect: InputParam = None + script: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.dialect = self.create_param(code="dialect", data_type=DataType.LABEL, is_required=False) + self.script = self.create_param(code="script", data_type=DataType.LABEL, is_required=False) + + +class EmotionDetectionOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class EmotionDetection(AssetNode[EmotionDetectionInputs, EmotionDetectionOutputs]): + """ + Emotion Detection is a process that involves analyzing text to identify and +categorize the emotional states or sentiments expressed by individuals, such as +happiness, sadness, anger, or fear. + + InputType: text + OutputType: label + """ + function: str = "emotion-detection" + input_type: str = DataType.TEXT + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = EmotionDetectionInputs + outputs_class: Type[TO] = EmotionDetectionOutputs + + +class TextSpamDetectionInputs(Inputs): + text: InputParam = None + language: InputParam = None + dialect: InputParam = None + script: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.dialect = self.create_param(code="dialect", data_type=DataType.LABEL, is_required=False) + self.script = self.create_param(code="script", data_type=DataType.LABEL, is_required=False) + + +class TextSpamDetectionOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class TextSpamDetection(AssetNode[TextSpamDetectionInputs, TextSpamDetectionOutputs]): + """ + Text Spam Detection is a process that involves analyzing and identifying +unsolicited or irrelevant messages within text communications, typically using +algorithms and machine learning techniques to filter out spam and ensure the +integrity of the communication platform. + + InputType: text + OutputType: label + """ + function: str = "text-spam-detection" + input_type: str = DataType.TEXT + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = TextSpamDetectionInputs + outputs_class: Type[TO] = TextSpamDetectionOutputs + + +class TranslationInputs(Inputs): + text: InputParam = None + sourcelanguage: InputParam = None + targetlanguage: InputParam = None + script_in: InputParam = None + script_out: InputParam = None + dialect_in: InputParam = None + dialect_out: InputParam = None + context: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.sourcelanguage = self.create_param(code="sourcelanguage", data_type=DataType.LABEL, is_required=True) + self.targetlanguage = self.create_param(code="targetlanguage", data_type=DataType.LABEL, is_required=True) + self.script_in = self.create_param(code="script_in", data_type=DataType.LABEL, is_required=False) + self.script_out = self.create_param(code="script_out", data_type=DataType.LABEL, is_required=False) + self.dialect_in = self.create_param(code="dialect_in", data_type=DataType.LABEL, is_required=False) + self.dialect_out = self.create_param(code="dialect_out", data_type=DataType.LABEL, is_required=False) + self.context = self.create_param(code="context", data_type=DataType.LABEL, is_required=False) + + +class TranslationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class Translation(AssetNode[TranslationInputs, TranslationOutputs]): + """ + Translation is the process of converting text from one language into an +equivalent text in another language, preserving the original meaning and +context. + + InputType: text + OutputType: text + """ + function: str = "translation" + input_type: str = DataType.TEXT + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = TranslationInputs + outputs_class: Type[TO] = TranslationOutputs + + +class VoiceActivityDetectionInputs(Inputs): + audio: InputParam = None + onset: InputParam = None + offset: InputParam = None + min_duration_on: InputParam = None + min_duration_off: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.audio = self.create_param(code="audio", data_type=DataType.AUDIO, is_required=True) + self.onset = self.create_param(code="onset", data_type=DataType.TEXT, is_required=False) + self.offset = self.create_param(code="offset", data_type=DataType.TEXT, is_required=False) + self.min_duration_on = self.create_param(code="min_duration_on", data_type=DataType.TEXT, is_required=False) + self.min_duration_off = self.create_param(code="min_duration_off", data_type=DataType.TEXT, is_required=False) + + +class VoiceActivityDetectionOutputs(Outputs): + data: OutputParam = None + audio: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.AUDIO) + self.audio = self.create_param(code="audio", data_type=DataType.AUDIO) + + +class VoiceActivityDetection(BaseSegmentor[VoiceActivityDetectionInputs, VoiceActivityDetectionOutputs]): + """ + Voice Activity Detection (VAD) is a technology that identifies the presence or +absence of human speech within an audio signal, enabling systems to distinguish +between spoken words and background noise. + + InputType: audio + OutputType: audio + """ + function: str = "voice-activity-detection" + input_type: str = DataType.AUDIO + output_type: str = DataType.AUDIO + + inputs_class: Type[TI] = VoiceActivityDetectionInputs + outputs_class: Type[TO] = VoiceActivityDetectionOutputs + + +class SpeechEmbeddingInputs(Inputs): + audio: InputParam = None + language: InputParam = None + dialect: InputParam = None + script: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.audio = self.create_param(code="audio", data_type=DataType.AUDIO, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.dialect = self.create_param(code="dialect", data_type=DataType.LABEL, is_required=False) + self.script = self.create_param(code="script", data_type=DataType.LABEL, is_required=False) + + +class SpeechEmbeddingOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class SpeechEmbedding(AssetNode[SpeechEmbeddingInputs, SpeechEmbeddingOutputs]): + """ + Speech Embedding is a process that transforms spoken language into a fixed- +dimensional vector representation, capturing essential features and +characteristics of the speech for tasks such as recognition, classification, +and analysis. + + InputType: audio + OutputType: text + """ + function: str = "speech-embedding" + input_type: str = DataType.AUDIO + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = SpeechEmbeddingInputs + outputs_class: Type[TO] = SpeechEmbeddingOutputs + + +class SubtitlingTranslationInputs(Inputs): + text: InputParam = None + sourcelanguage: InputParam = None + dialect_in: InputParam = None + target_supplier: InputParam = None + targetlanguages: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.sourcelanguage = self.create_param(code="sourcelanguage", data_type=DataType.LABEL, is_required=True) + self.dialect_in = self.create_param(code="dialect_in", data_type=DataType.LABEL, is_required=False) + self.target_supplier = self.create_param(code="target_supplier", data_type=DataType.LABEL, is_required=False) + self.targetlanguages = self.create_param(code="targetlanguages", data_type=DataType.LABEL, is_required=False) + + +class SubtitlingTranslationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class SubtitlingTranslation(AssetNode[SubtitlingTranslationInputs, SubtitlingTranslationOutputs]): + """ + Subtitling Translation is the process of converting spoken dialogue from one +language into written text in another language, which is then displayed on- +screen to aid viewers in understanding the content. + + InputType: text + OutputType: text + """ + function: str = "subtitling-translation" + input_type: str = DataType.TEXT + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = SubtitlingTranslationInputs + outputs_class: Type[TO] = SubtitlingTranslationOutputs + + +class TextGenerationInputs(Inputs): + text: InputParam = None + prompt: InputParam = None + context: InputParam = None + language: InputParam = None + script: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.prompt = self.create_param(code="prompt", data_type=DataType.TEXT, is_required=False) + self.context = self.create_param(code="context", data_type=DataType.TEXT, is_required=False) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=False) + self.script = self.create_param(code="script", data_type=DataType.LABEL, is_required=False) + + +class TextGenerationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class TextGeneration(AssetNode[TextGenerationInputs, TextGenerationOutputs]): + """ + Text Generation is a process in which artificial intelligence models, such as +neural networks, produce coherent and contextually relevant text based on a +given input or prompt, often mimicking human writing styles and patterns. + + InputType: text + OutputType: text + """ + function: str = "text-generation" + input_type: str = DataType.TEXT + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = TextGenerationInputs + outputs_class: Type[TO] = TextGenerationOutputs + + +class VideoUnderstandingInputs(Inputs): + video: InputParam = None + text: InputParam = None + language: InputParam = None + dialect: InputParam = None + script: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.video = self.create_param(code="video", data_type=DataType.VIDEO, is_required=True) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.dialect = self.create_param(code="dialect", data_type=DataType.LABEL, is_required=False) + self.script = self.create_param(code="script", data_type=DataType.LABEL, is_required=False) + + +class VideoUnderstandingOutputs(Outputs): + text: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT) + + +class VideoUnderstanding(AssetNode[VideoUnderstandingInputs, VideoUnderstandingOutputs]): + """ + Video Understanding is the process of analyzing and interpreting video content +to extract meaningful information, such as identifying objects, actions, +events, and contextual relationships within the footage. + + InputType: video + OutputType: text + """ + function: str = "video-understanding" + input_type: str = DataType.VIDEO + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = VideoUnderstandingInputs + outputs_class: Type[TO] = VideoUnderstandingOutputs + + +class TextToVideoGenerationInputs(Inputs): + text: InputParam = None + language: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=False) + + +class TextToVideoGenerationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.VIDEO) + + +class TextToVideoGeneration(AssetNode[TextToVideoGenerationInputs, TextToVideoGenerationOutputs]): + """ + Text To Video Generation is a process that converts written descriptions or +scripts into dynamic, visual video content using advanced algorithms and +artificial intelligence. + + InputType: text + OutputType: video + """ + function: str = "text-to-video-generation" + input_type: str = DataType.TEXT + output_type: str = DataType.VIDEO + + inputs_class: Type[TI] = TextToVideoGenerationInputs + outputs_class: Type[TO] = TextToVideoGenerationOutputs + + +class TextNormalizationInputs(Inputs): + text: InputParam = None + language: InputParam = None + settings: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=False) + self.settings = self.create_param(code="settings", data_type=DataType.TEXT, is_required=False) + + +class TextNormalizationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.LABEL) + + +class TextNormalization(AssetNode[TextNormalizationInputs, TextNormalizationOutputs]): + """ + Text normalization is the process of transforming text into a standard, +consistent format by correcting spelling errors, converting all characters to a +uniform case, removing punctuation, and expanding abbreviations to improve the +text's readability and usability for further processing or analysis. + + InputType: text + OutputType: label + """ + function: str = "text-normalization" + input_type: str = DataType.TEXT + output_type: str = DataType.LABEL + + inputs_class: Type[TI] = TextNormalizationInputs + outputs_class: Type[TO] = TextNormalizationOutputs + + +class SpeechRecognitionInputs(Inputs): + language: InputParam = None + dialect: InputParam = None + voice: InputParam = None + source_audio: InputParam = None + script: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.language = self.create_param(code="language", data_type=DataType.LABEL, is_required=True) + self.dialect = self.create_param(code="dialect", data_type=DataType.LABEL, is_required=False) + self.voice = self.create_param(code="voice", data_type=DataType.LABEL, is_required=False) + self.source_audio = self.create_param(code="source_audio", data_type=DataType.AUDIO, is_required=True) + self.script = self.create_param(code="script", data_type=DataType.LABEL, is_required=False) + + +class SpeechRecognitionOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class SpeechRecognition(AssetNode[SpeechRecognitionInputs, SpeechRecognitionOutputs]): + """ + Speech recognition is a technology that enables a computer or device to +identify and process spoken language, converting it into text. + + InputType: audio + OutputType: text + """ + function: str = "speech-recognition" + input_type: str = DataType.AUDIO + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = SpeechRecognitionInputs + outputs_class: Type[TO] = SpeechRecognitionOutputs + + +class SubtitlingInputs(Inputs): + source_audio: InputParam = None + sourcelanguage: InputParam = None + dialect_in: InputParam = None + source_supplier: InputParam = None + target_supplier: InputParam = None + targetlanguages: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.source_audio = self.create_param(code="source_audio", data_type=DataType.AUDIO, is_required=True) + self.sourcelanguage = self.create_param(code="sourcelanguage", data_type=DataType.LABEL, is_required=True) + self.dialect_in = self.create_param(code="dialect_in", data_type=DataType.LABEL, is_required=False) + self.source_supplier = self.create_param(code="source_supplier", data_type=DataType.LABEL, is_required=False) + self.target_supplier = self.create_param(code="target_supplier", data_type=DataType.LABEL, is_required=False) + self.targetlanguages = self.create_param(code="targetlanguages", data_type=DataType.LABEL, is_required=False) + + +class SubtitlingOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.TEXT) + + +class Subtitling(AssetNode[SubtitlingInputs, SubtitlingOutputs]): + """ + Subtitling is the process of displaying written text on a screen to represent +the spoken dialogue, narration, or other audio elements in a video, typically +to aid viewers who are deaf or hard of hearing, or to provide translations for +audiences who speak different languages. + + InputType: audio + OutputType: text + """ + function: str = "subtitling" + input_type: str = DataType.AUDIO + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = SubtitlingInputs + outputs_class: Type[TO] = SubtitlingOutputs + + +class ClassificationMetricInputs(Inputs): + hypotheses: InputParam = None + references: InputParam = None + lowerIsBetter: InputParam = None + sources: InputParam = None + score_identifier: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.hypotheses = self.create_param(code="hypotheses", data_type=DataType.LABEL, is_required=True) + self.references = self.create_param(code="references", data_type=DataType.LABEL, is_required=True) + self.lowerIsBetter = self.create_param(code="lowerIsBetter", data_type=DataType.TEXT, is_required=False) + self.sources = self.create_param(code="sources", data_type=DataType.TEXT, is_required=False) + self.score_identifier = self.create_param(code="score_identifier", data_type=DataType.TEXT, is_required=True) + + +class ClassificationMetricOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.NUMBER) + + +class ClassificationMetric(AssetNode[ClassificationMetricInputs, ClassificationMetricOutputs]): + """ + A Classification Metric is a quantitative measure used to evaluate the quality +and effectiveness of classification models. + + InputType: text + OutputType: text + """ + function: str = "classification-metric" + input_type: str = DataType.TEXT + output_type: str = DataType.TEXT + + inputs_class: Type[TI] = ClassificationMetricInputs + outputs_class: Type[TO] = ClassificationMetricOutputs + + +class TextToImageGenerationInputs(Inputs): + text: InputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.text = self.create_param(code="text", data_type=DataType.TEXT, is_required=True) + + +class TextToImageGenerationOutputs(Outputs): + data: OutputParam = None + + def __init__(self, node=None): + super().__init__(node=node) + self.data = self.create_param(code="data", data_type=DataType.IMAGE) + + +class TextToImageGeneration(AssetNode[TextToImageGenerationInputs, TextToImageGenerationOutputs]): + """ + Text To Image Generation is a process where a system creates visual images +based on descriptive text input, translating written language into +corresponding graphical representations. + + InputType: text + OutputType: image + """ + function: str = "text-to-image-generation" + input_type: str = DataType.TEXT + output_type: str = DataType.IMAGE + + inputs_class: Type[TI] = TextToImageGenerationInputs + outputs_class: Type[TO] = TextToImageGenerationOutputs + + + +class Pipeline(DefaultPipeline): + + def object_detection(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> ObjectDetection: + """ + Object Detection is a computer vision technology that identifies and locates +objects within an image, typically by drawing bounding boxes around the +detected objects and classifying them into predefined categories. + """ + return ObjectDetection(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def language_identification(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> LanguageIdentification: + """ + Language Identification is the process of automatically determining the +language in which a given piece of text is written. + """ + return LanguageIdentification(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def ocr(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> Ocr: + """ + OCR, or Optical Character Recognition, is a technology that converts different +types of documents, such as scanned paper documents, PDFs, or images captured +by a digital camera, into editable and searchable data by recognizing and +extracting text from the images. + """ + return Ocr(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def script_execution(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> ScriptExecution: + """ + Script Execution refers to the process of running a set of programmed +instructions or code within a computing environment, enabling the automated +performance of tasks, calculations, or operations as defined by the script. + """ + return ScriptExecution(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def image_label_detection(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> ImageLabelDetection: + """ + Image Label Detection is a function that automatically identifies and assigns +descriptive tags or labels to objects, scenes, or elements within an image, +enabling easier categorization, search, and analysis of visual content. + """ + return ImageLabelDetection(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def image_captioning(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> ImageCaptioning: + """ + Image Captioning is a process that involves generating a textual description of +an image, typically using machine learning models to analyze the visual content +and produce coherent and contextually relevant sentences that describe the +objects, actions, and scenes depicted in the image. + """ + return ImageCaptioning(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def audio_language_identification(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> AudioLanguageIdentification: + """ + Audio Language Identification is a process that involves analyzing an audio +recording to determine the language being spoken. + """ + return AudioLanguageIdentification(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def asr_age_classification(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> AsrAgeClassification: + """ + The ASR Age Classification function is designed to analyze audio recordings of +speech to determine the speaker's age group by leveraging automatic speech +recognition (ASR) technology and machine learning algorithms. + """ + return AsrAgeClassification(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def benchmark_scoring_mt(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> BenchmarkScoringMt: + """ + Benchmark Scoring MT is a function designed to evaluate and score machine +translation systems by comparing their output against a set of predefined +benchmarks, thereby assessing their accuracy and performance. + """ + return BenchmarkScoringMt(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def asr_gender_classification(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> AsrGenderClassification: + """ + The ASR Gender Classification function analyzes audio recordings to determine +and classify the speaker's gender based on their voice characteristics. + """ + return AsrGenderClassification(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def base_model(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> BaseModel: + """ + The Base-Model function serves as a foundational framework designed to provide +essential features and capabilities upon which more specialized or advanced +models can be built and customized. + """ + return BaseModel(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def language_identification_audio(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> LanguageIdentificationAudio: + """ + The Language Identification Audio function analyzes audio input to determine +and identify the language being spoken. + """ + return LanguageIdentificationAudio(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def loglikelihood(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> Loglikelihood: + """ + The Log Likelihood function measures the probability of observing the given +data under a specific statistical model by taking the natural logarithm of the +likelihood function, thereby transforming the product of probabilities into a +sum, which simplifies the process of optimization and parameter estimation. + """ + return Loglikelihood(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def video_embedding(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> VideoEmbedding: + """ + Video Embedding is a process that transforms video content into a fixed- +dimensional vector representation, capturing essential features and patterns to +facilitate tasks such as retrieval, classification, and recommendation. + """ + return VideoEmbedding(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def text_segmenation(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> TextSegmenation: + """ + Text Segmentation is the process of dividing a continuous text into meaningful +units, such as words, sentences, or topics, to facilitate easier analysis and +understanding. + """ + return TextSegmenation(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def image_embedding(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> ImageEmbedding: + """ + Image Embedding is a process that transforms an image into a fixed-dimensional +vector representation, capturing its essential features and enabling efficient +comparison, retrieval, and analysis in various machine learning and computer +vision tasks. + """ + return ImageEmbedding(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def image_manipulation(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> ImageManipulation: + """ + Image Manipulation refers to the process of altering or enhancing digital +images using various techniques and tools to achieve desired visual effects, +correct imperfections, or transform the image's appearance. + """ + return ImageManipulation(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def image_to_video_generation(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> ImageToVideoGeneration: + """ + The Image To Video Generation function transforms a series of static images +into a cohesive, dynamic video sequence, often incorporating transitions, +effects, and synchronization with audio to create a visually engaging +narrative. + """ + return ImageToVideoGeneration(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def audio_forced_alignment(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> AudioForcedAlignment: + """ + Audio Forced Alignment is a process that synchronizes a given audio recording +with its corresponding transcript by precisely aligning each spoken word or +phoneme to its exact timing within the audio. + """ + return AudioForcedAlignment(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def benchmark_scoring_asr(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> BenchmarkScoringAsr: + """ + Benchmark Scoring ASR is a function that evaluates and compares the performance +of automatic speech recognition systems by analyzing their accuracy, speed, and +other relevant metrics against a standardized set of benchmarks. + """ + return BenchmarkScoringAsr(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def visual_question_answering(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> VisualQuestionAnswering: + """ + Visual Question Answering (VQA) is a task in artificial intelligence that +involves analyzing an image and providing accurate, contextually relevant +answers to questions posed about the visual content of that image. + """ + return VisualQuestionAnswering(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def document_image_parsing(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> DocumentImageParsing: + """ + Document Image Parsing is the process of analyzing and converting scanned or +photographed images of documents into structured, machine-readable formats by +identifying and extracting text, layout, and other relevant information. + """ + return DocumentImageParsing(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def document_information_extraction(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> DocumentInformationExtraction: + """ + Document Information Extraction is the process of automatically identifying, +extracting, and structuring relevant data from unstructured or semi-structured +documents, such as invoices, receipts, contracts, and forms, to facilitate +easier data management and analysis. + """ + return DocumentInformationExtraction(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def depth_estimation(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> DepthEstimation: + """ + Depth estimation is a computational process that determines the distance of +objects from a viewpoint, typically using visual data from cameras or sensors +to create a three-dimensional understanding of a scene. + """ + return DepthEstimation(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def video_generation(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> VideoGeneration: + """ + Video Generation is the process of creating video content through automated or +semi-automated means, often utilizing algorithms, artificial intelligence, or +software tools to produce visual and audio elements that can range from simple +animations to complex, realistic scenes. + """ + return VideoGeneration(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def referenceless_audio_generation_metric(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> ReferencelessAudioGenerationMetric: + """ + The Referenceless Audio Generation Metric is a tool designed to evaluate the +quality of generated audio content without the need for a reference or original +audio sample for comparison. + """ + return ReferencelessAudioGenerationMetric(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def multi_class_image_classification(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> MultiClassImageClassification: + """ + Multi Class Image Classification is a machine learning task where an algorithm +is trained to categorize images into one of several predefined classes or +categories based on their visual content. + """ + return MultiClassImageClassification(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def semantic_segmentation(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> SemanticSegmentation: + """ + Semantic segmentation is a computer vision process that involves classifying +each pixel in an image into a predefined category, effectively partitioning the +image into meaningful segments based on the objects or regions they represent. + """ + return SemanticSegmentation(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def instance_segmentation(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> InstanceSegmentation: + """ + Instance segmentation is a computer vision task that involves detecting and +delineating each distinct object within an image, assigning a unique label and +precise boundary to every individual instance of objects, even if they belong +to the same category. + """ + return InstanceSegmentation(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def image_colorization(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> ImageColorization: + """ + Image colorization is a process that involves adding color to grayscale images, +transforming them from black-and-white to full-color representations, often +using advanced algorithms and machine learning techniques to predict and apply +the appropriate hues and shades. + """ + return ImageColorization(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def audio_generation_metric(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> AudioGenerationMetric: + """ + The Audio Generation Metric is a quantitative measure used to evaluate the +quality, accuracy, and overall performance of audio generated by artificial +intelligence systems, often considering factors such as fidelity, +intelligibility, and similarity to human-produced audio. + """ + return AudioGenerationMetric(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def image_impainting(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> ImageImpainting: + """ + Image inpainting is a process that involves filling in missing or damaged parts +of an image in a way that is visually coherent and seamlessly blends with the +surrounding areas, often using advanced algorithms and techniques to restore +the image to its original or intended appearance. + """ + return ImageImpainting(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def style_transfer(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> StyleTransfer: + """ + Style Transfer is a technique in artificial intelligence that applies the +visual style of one image (such as the brushstrokes of a famous painting) to +the content of another image, effectively blending the artistic elements of the +first image with the subject matter of the second. + """ + return StyleTransfer(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def multi_class_text_classification(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> MultiClassTextClassification: + """ + Multi Class Text Classification is a natural language processing task that +involves categorizing a given text into one of several predefined classes or +categories based on its content. + """ + return MultiClassTextClassification(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def text_embedding(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> TextEmbedding: + """ + Text embedding is a process that converts text into numerical vectors, +capturing the semantic meaning and contextual relationships of words or +phrases, enabling machines to understand and analyze natural language more +effectively. + """ + return TextEmbedding(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def multi_label_text_classification(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> MultiLabelTextClassification: + """ + Multi Label Text Classification is a natural language processing task where a +given text is analyzed and assigned multiple relevant labels or categories from +a predefined set, allowing for the text to belong to more than one category +simultaneously. + """ + return MultiLabelTextClassification(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def text_reconstruction(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> TextReconstruction: + """ + Text Reconstruction is a process that involves piecing together fragmented or +incomplete text data to restore it to its original, coherent form. + """ + return TextReconstruction(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def fact_checking(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> FactChecking: + """ + Fact Checking is the process of verifying the accuracy and truthfulness of +information, statements, or claims by cross-referencing with reliable sources +and evidence. + """ + return FactChecking(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def speech_classification(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> SpeechClassification: + """ + Speech Classification is a process that involves analyzing and categorizing +spoken language into predefined categories or classes based on various features +such as tone, pitch, and linguistic content. + """ + return SpeechClassification(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def intent_classification(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> IntentClassification: + """ + Intent Classification is a natural language processing task that involves +analyzing and categorizing user text input to determine the underlying purpose +or goal behind the communication, such as booking a flight, asking for weather +information, or setting a reminder. + """ + return IntentClassification(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def part_of_speech_tagging(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> PartOfSpeechTagging: + """ + Part of Speech Tagging is a natural language processing task that involves +assigning each word in a sentence its corresponding part of speech, such as +noun, verb, adjective, or adverb, based on its role and context within the +sentence. + """ + return PartOfSpeechTagging(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def metric_aggregation(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> MetricAggregation: + """ + Metric Aggregation is a function that computes and summarizes numerical data by +applying statistical operations, such as averaging, summing, or finding the +minimum and maximum values, to provide insights and facilitate analysis of +large datasets. + """ + return MetricAggregation(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def dialect_detection(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> DialectDetection: + """ + Dialect Detection is a function that identifies and classifies the specific +regional or social variations of a language spoken or written by an individual, +enabling the recognition of distinct linguistic patterns and nuances associated +with different dialects. + """ + return DialectDetection(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def inverse_text_normalization(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> InverseTextNormalization: + """ + Inverse Text Normalization is the process of converting spoken or written +language in its normalized form, such as numbers, dates, and abbreviations, +back into their original, more complex or detailed textual representations. + """ + return InverseTextNormalization(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def text_to_audio(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> TextToAudio: + """ + The Text to Audio function converts written text into spoken words, allowing +users to listen to the content instead of reading it. + """ + return TextToAudio(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def fill_text_mask(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> FillTextMask: + """ + The "Fill Text Mask" function takes a text input with masked or placeholder +characters and replaces those placeholders with specified or contextually +appropriate characters to generate a complete and coherent text output. + """ + return FillTextMask(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def video_content_moderation(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> VideoContentModeration: + """ + Video Content Moderation is the process of reviewing, analyzing, and filtering +video content to ensure it adheres to community guidelines, legal standards, +and platform policies, thereby preventing the dissemination of inappropriate, +harmful, or illegal material. + """ + return VideoContentModeration(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def extract_audio_from_video(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> ExtractAudioFromVideo: + """ + The "Extract Audio From Video" function allows users to separate and save the +audio track from a video file, enabling them to obtain just the sound without +the accompanying visual content. + """ + return ExtractAudioFromVideo(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def image_compression(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> ImageCompression: + """ + Image compression is a process that reduces the file size of an image by +removing redundant or non-essential data, while maintaining an acceptable level +of visual quality. + """ + return ImageCompression(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def multilingual_speech_recognition(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> MultilingualSpeechRecognition: + """ + Multilingual Speech Recognition is a technology that enables the automatic +transcription of spoken language into text across multiple languages, allowing +for seamless communication and understanding in diverse linguistic contexts. + """ + return MultilingualSpeechRecognition(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def referenceless_text_generation_metric(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> ReferencelessTextGenerationMetric: + """ + The Referenceless Text Generation Metric is a method for evaluating the quality +of generated text without requiring a reference text for comparison, often +leveraging models or algorithms to assess coherence, relevance, and fluency +based on intrinsic properties of the text itself. + """ + return ReferencelessTextGenerationMetric(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def text_generation_metric_default(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> TextGenerationMetricDefault: + """ + The "Text Generation Metric Default" function provides a standard set of +evaluation metrics for assessing the quality and performance of text generation +models. + """ + return TextGenerationMetricDefault(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def noise_removal(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> NoiseRemoval: + """ + Noise Removal is a process that involves identifying and eliminating unwanted +random variations or disturbances from an audio signal to enhance the clarity +and quality of the underlying information. + """ + return NoiseRemoval(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def audio_reconstruction(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> AudioReconstruction: + """ + Audio Reconstruction is the process of restoring or recreating audio signals +from incomplete, damaged, or degraded recordings to achieve a high-quality, +accurate representation of the original sound. + """ + return AudioReconstruction(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def voice_cloning(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> VoiceCloning: + """ + Voice cloning is a technology that uses artificial intelligence to create a +digital replica of a person's voice, allowing for the generation of speech that +mimics the tone, pitch, and speaking style of the original speaker. + """ + return VoiceCloning(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def diacritization(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> Diacritization: + """ + Diacritization is the process of adding diacritical marks to letters in a text +to indicate pronunciation, stress, tone, or meaning, often used in languages +such as Arabic, Hebrew, and Vietnamese to provide clarity and accuracy in +written communication. + """ + return Diacritization(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def audio_emotion_detection(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> AudioEmotionDetection: + """ + Audio Emotion Detection is a technology that analyzes vocal characteristics and +patterns in audio recordings to identify and classify the emotional state of +the speaker. + """ + return AudioEmotionDetection(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def text_summarization(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> TextSummarization: + """ + Text summarization is the process of condensing a large body of text into a +shorter version, capturing the main points and essential information while +maintaining coherence and meaning. + """ + return TextSummarization(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def entity_linking(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> EntityLinking: + """ + Entity Linking is the process of identifying and connecting mentions of +entities within a text to their corresponding entries in a structured knowledge +base, thereby enabling the disambiguation of terms and enhancing the +understanding of the text's context. + """ + return EntityLinking(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def text_generation_metric(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> TextGenerationMetric: + """ + A Text Generation Metric is a quantitative measure used to evaluate the quality +and effectiveness of text produced by natural language processing models, often +assessing aspects such as coherence, relevance, fluency, and adherence to given +prompts or instructions. + """ + return TextGenerationMetric(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def split_on_linebreak(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> SplitOnLinebreak: + """ + The "Split On Linebreak" function divides a given string into a list of +substrings, using linebreaks (newline characters) as the points of separation. + """ + return SplitOnLinebreak(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def sentiment_analysis(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> SentimentAnalysis: + """ + Sentiment Analysis is a natural language processing technique used to determine +and classify the emotional tone or subjective information expressed in a piece +of text, such as identifying whether the sentiment is positive, negative, or +neutral. + """ + return SentimentAnalysis(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def keyword_spotting(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> KeywordSpotting: + """ + Keyword Spotting is a function that enables the detection and identification of +specific words or phrases within a stream of audio, often used in voice- +activated systems to trigger actions or commands based on recognized keywords. + """ + return KeywordSpotting(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def text_classification(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> TextClassification: + """ + Text Classification is a natural language processing task that involves +categorizing text into predefined labels or classes based on its content, +enabling automated organization, filtering, and analysis of large volumes of +textual data. + """ + return TextClassification(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def other__multipurpose_(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> OtherMultipurpose: + """ + The "Other (Multipurpose)" function serves as a versatile category designed to +accommodate a wide range of tasks and activities that do not fit neatly into +predefined classifications, offering flexibility and adaptability for various +needs. + """ + return OtherMultipurpose(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def speech_synthesis(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> SpeechSynthesis: + """ + Speech synthesis is the artificial production of human speech, typically +achieved through software or hardware systems that convert text into spoken +words, enabling machines to communicate verbally with users. + """ + return SpeechSynthesis(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def audio_intent_detection(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> AudioIntentDetection: + """ + Audio Intent Detection is a process that involves analyzing audio signals to +identify and interpret the underlying intentions or purposes behind spoken +words, enabling systems to understand and respond appropriately to human +speech. + """ + return AudioIntentDetection(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def video_label_detection(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> VideoLabelDetection: + """ + Video Label Detection is a function that automatically identifies and tags +various objects, scenes, activities, and other relevant elements within a +video, providing descriptive labels that enhance searchability and content +organization. + """ + return VideoLabelDetection(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def asr_quality_estimation(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> AsrQualityEstimation: + """ + ASR Quality Estimation is a process that evaluates the accuracy and reliability +of automatic speech recognition systems by analyzing their performance in +transcribing spoken language into text. + """ + return AsrQualityEstimation(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def audio_transcript_analysis(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> AudioTranscriptAnalysis: + """ + Audio Transcript Analysis is a process that involves converting spoken language +from audio recordings into written text, followed by examining and interpreting +the transcribed content to extract meaningful insights, identify patterns, and +derive actionable information. + """ + return AudioTranscriptAnalysis(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def search(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> Search: + """ + The "Search" function allows users to input keywords or phrases to quickly +locate specific information, files, or content within a database, website, or +application. + """ + return Search(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def video_forced_alignment(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> VideoForcedAlignment: + """ + Video Forced Alignment is a process that synchronizes video footage with +corresponding audio tracks by precisely aligning the visual and auditory +elements, ensuring that the movements of speakers' lips match the spoken words. + """ + return VideoForcedAlignment(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def viseme_generation(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> VisemeGeneration: + """ + Viseme Generation is the process of creating visual representations of +phonemes, which are the distinct units of sound in speech, to synchronize lip +movements with spoken words in animations or virtual avatars. + """ + return VisemeGeneration(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def topic_classification(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> TopicClassification: + """ + Topic Classification is a natural language processing function that categorizes +text into predefined topics or subjects based on its content, enabling +efficient organization and retrieval of information. + """ + return TopicClassification(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def offensive_language_identification(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> OffensiveLanguageIdentification: + """ + Offensive Language Identification is a function that analyzes text to detect +and flag language that is abusive, harmful, or inappropriate, helping to +maintain a respectful and safe communication environment. + """ + return OffensiveLanguageIdentification(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def speech_translation(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> SpeechTranslation: + """ + Speech Translation is a technology that converts spoken language in real-time +from one language to another, enabling seamless communication between speakers +of different languages. + """ + return SpeechTranslation(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def speaker_diarization_audio(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> SpeakerDiarizationAudio: + """ + Speaker Diarization Audio is a process that involves segmenting an audio +recording into distinct sections, each corresponding to a different speaker, in +order to identify and differentiate between multiple speakers within the same +audio stream. + """ + return SpeakerDiarizationAudio(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def audio_transcript_improvement(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> AudioTranscriptImprovement: + """ + Audio Transcript Improvement is a function that enhances the accuracy and +clarity of transcribed audio recordings by correcting errors, refining +language, and ensuring the text faithfully represents the original spoken +content. + """ + return AudioTranscriptImprovement(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def speech_non_speech_classification(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> SpeechNonSpeechClassification: + """ + The function "Speech or Non-Speech Classification" is designed to analyze audio +input and determine whether the sound is human speech or non-speech noise, +enabling applications such as voice recognition systems to filter out +irrelevant background sounds. + """ + return SpeechNonSpeechClassification(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def text_denormalization(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> TextDenormalization: + """ + Text Denormalization is the process of converting abbreviated, contracted, or +otherwise simplified text into its full, standard form, often to improve +readability and ensure consistency in natural language processing tasks. + """ + return TextDenormalization(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def image_content_moderation(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> ImageContentModeration: + """ + Image Content Moderation is a process that involves analyzing and filtering +images to detect and manage inappropriate, harmful, or sensitive content, +ensuring compliance with community guidelines and legal standards. + """ + return ImageContentModeration(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def referenceless_text_generation_metric_default(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> ReferencelessTextGenerationMetricDefault: + """ + The Referenceless Text Generation Metric Default is a function designed to +evaluate the quality of generated text without relying on reference texts for +comparison. + """ + return ReferencelessTextGenerationMetricDefault(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def named_entity_recognition(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> NamedEntityRecognition: + """ + Named Entity Recognition (NER) is a natural language processing task that +involves identifying and classifying proper nouns in text into predefined +categories such as names of people, organizations, locations, dates, and other +entities. + """ + return NamedEntityRecognition(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def text_content_moderation(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> TextContentModeration: + """ + Text Content Moderation is the process of reviewing, filtering, and managing +user-generated content to ensure it adheres to community guidelines, legal +standards, and platform policies, thereby maintaining a safe and respectful +online environment. + """ + return TextContentModeration(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def speaker_diarization_video(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> SpeakerDiarizationVideo: + """ + The Speaker Diarization Video function identifies and segments different +speakers in a video, attributing portions of the audio to individual speakers +to facilitate analysis and understanding of multi-speaker conversations. + """ + return SpeakerDiarizationVideo(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def split_on_silence(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> SplitOnSilence: + """ + The "Split On Silence" function divides an audio recording into separate +segments based on periods of silence, allowing for easier editing and analysis +of individual sections. + """ + return SplitOnSilence(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def emotion_detection(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> EmotionDetection: + """ + Emotion Detection is a process that involves analyzing text to identify and +categorize the emotional states or sentiments expressed by individuals, such as +happiness, sadness, anger, or fear. + """ + return EmotionDetection(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def text_spam_detection(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> TextSpamDetection: + """ + Text Spam Detection is a process that involves analyzing and identifying +unsolicited or irrelevant messages within text communications, typically using +algorithms and machine learning techniques to filter out spam and ensure the +integrity of the communication platform. + """ + return TextSpamDetection(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def translation(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> Translation: + """ + Translation is the process of converting text from one language into an +equivalent text in another language, preserving the original meaning and +context. + """ + return Translation(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def voice_activity_detection(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> VoiceActivityDetection: + """ + Voice Activity Detection (VAD) is a technology that identifies the presence or +absence of human speech within an audio signal, enabling systems to distinguish +between spoken words and background noise. + """ + return VoiceActivityDetection(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def speech_embedding(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> SpeechEmbedding: + """ + Speech Embedding is a process that transforms spoken language into a fixed- +dimensional vector representation, capturing essential features and +characteristics of the speech for tasks such as recognition, classification, +and analysis. + """ + return SpeechEmbedding(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def subtitling_translation(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> SubtitlingTranslation: + """ + Subtitling Translation is the process of converting spoken dialogue from one +language into written text in another language, which is then displayed on- +screen to aid viewers in understanding the content. + """ + return SubtitlingTranslation(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def text_generation(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> TextGeneration: + """ + Text Generation is a process in which artificial intelligence models, such as +neural networks, produce coherent and contextually relevant text based on a +given input or prompt, often mimicking human writing styles and patterns. + """ + return TextGeneration(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def video_understanding(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> VideoUnderstanding: + """ + Video Understanding is the process of analyzing and interpreting video content +to extract meaningful information, such as identifying objects, actions, +events, and contextual relationships within the footage. + """ + return VideoUnderstanding(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def text_to_video_generation(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> TextToVideoGeneration: + """ + Text To Video Generation is a process that converts written descriptions or +scripts into dynamic, visual video content using advanced algorithms and +artificial intelligence. + """ + return TextToVideoGeneration(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def text_normalization(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> TextNormalization: + """ + Text normalization is the process of transforming text into a standard, +consistent format by correcting spelling errors, converting all characters to a +uniform case, removing punctuation, and expanding abbreviations to improve the +text's readability and usability for further processing or analysis. + """ + return TextNormalization(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def speech_recognition(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> SpeechRecognition: + """ + Speech recognition is a technology that enables a computer or device to +identify and process spoken language, converting it into text. + """ + return SpeechRecognition(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def subtitling(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> Subtitling: + """ + Subtitling is the process of displaying written text on a screen to represent +the spoken dialogue, narration, or other audio elements in a video, typically +to aid viewers who are deaf or hard of hearing, or to provide translations for +audiences who speak different languages. + """ + return Subtitling(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def classification_metric(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> ClassificationMetric: + """ + A Classification Metric is a quantitative measure used to evaluate the quality +and effectiveness of classification models. + """ + return ClassificationMetric(*args, asset_id=asset_id, pipeline=self, **kwargs) + + def text_to_image_generation(self, asset_id: Union[str, asset.Asset], *args, **kwargs) -> TextToImageGeneration: + """ + Text To Image Generation is a process where a system creates visual images +based on descriptive text input, translating written language into +corresponding graphical representations. + """ + return TextToImageGeneration(*args, asset_id=asset_id, pipeline=self, **kwargs) + diff --git a/pyproject.toml b/pyproject.toml index 73980717..5b0ded4b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,7 +51,8 @@ dependencies = [ "filetype>=1.2.0", "click>=7.1.2,<8.0.0", "PyYAML>=6.0.1", - "dataclasses-json>=0.5.2" + "dataclasses-json>=0.5.2", + "Jinja2==3.1.4", ] [project.urls] diff --git a/tests/functional/agent/agent_functional_test.py b/tests/functional/agent/agent_functional_test.py index f58dcb63..f6ff0408 100644 --- a/tests/functional/agent/agent_functional_test.py +++ b/tests/functional/agent/agent_functional_test.py @@ -20,7 +20,6 @@ load_dotenv() from aixplain.factories import AgentFactory -from aixplain.modules.agent import ModelTool, PipelineTool from aixplain.enums.supplier import Supplier import pytest @@ -38,6 +37,9 @@ def run_input_map(request): def test_end2end(run_input_map): + for agent in AgentFactory.list()["results"]: + agent.delete() + tools = [] if "model_tools" in run_input_map: for tool in run_input_map["model_tools"]: @@ -48,15 +50,15 @@ def test_end2end(run_input_map): ]: tool["supplier"] = supplier break - tools.append(ModelTool(function=tool["function"], supplier=tool["supplier"])) + tools.append(AgentFactory.create_model_tool(**tool)) if "pipeline_tools" in run_input_map: for tool in run_input_map["pipeline_tools"]: - tools.append(PipelineTool(description=tool["description"], pipeline=tool["pipeline_id"])) + tools.append(AgentFactory.create_pipeline_tool(pipeline=tool["pipeline_id"], description=tool["description"])) print(f"Creating agent with tools: {tools}") agent = AgentFactory.create(name=run_input_map["agent_name"], llm_id=run_input_map["llm_id"], tools=tools) print(f"Agent created: {agent.__dict__}") print("Running agent") - response = agent.run(query=run_input_map["query"]) + response = agent.run(data=run_input_map["query"]) print(f"Agent response: {response}") assert response is not None assert response["completed"] is True diff --git a/tests/functional/agent/data/agent_test_end2end.json b/tests/functional/agent/data/agent_test_end2end.json index 147928fe..94bfc94b 100644 --- a/tests/functional/agent/data/agent_test_end2end.json +++ b/tests/functional/agent/data/agent_test_end2end.json @@ -8,6 +8,11 @@ { "function": "translation", "supplier": "AWS" + }, + { + "model": "60ddefca8d38c51c58860108", + "function": null, + "supplier": null } ] } diff --git a/tests/functional/model/hf_onboarding_test.py b/tests/functional/model/hf_onboarding_test.py index 47a38361..fa68d2e8 100644 --- a/tests/functional/model/hf_onboarding_test.py +++ b/tests/functional/model/hf_onboarding_test.py @@ -13,7 +13,7 @@ def test_deploy_model(): # Start the deployment model_name = "Test Model" repo_id = "tiiuae/falcon-7b" - response = ModelFactory.deploy_huggingface_model(model_name, repo_id, config.HF_TOKEN) + response = ModelFactory.deploy_huggingface_model(model_name, repo_id, hf_token=config.HF_TOKEN) assert "id" in response.keys() # Check for status @@ -30,31 +30,31 @@ def test_deploy_model(): delete_asset(model_id, config.TEAM_API_KEY) -@pytest.mark.skip(reason="Model Deployment is deactivated for improvements.") +# @pytest.mark.skip(reason="Model Deployment is deactivated for improvements.") def test_nonexistent_model(): # Start the deployment model_name = "Test Model" repo_id = "nonexistent-supplier/nonexistent-model" - response = ModelFactory.deploy_huggingface_model(model_name, repo_id, config.HF_TOKEN) + response = ModelFactory.deploy_huggingface_model(model_name, repo_id, hf_token=config.HF_TOKEN) assert response["statusCode"] == 400 assert response["message"] == "err.unable_to_onboard_model" -@pytest.mark.skip(reason="Model Deployment is deactivated for improvements.") +# @pytest.mark.skip(reason="Model Deployment is deactivated for improvements.") def test_size_limit(): # Start the deployment model_name = "Test Model" repo_id = "tiiuae/falcon-40b" - response = ModelFactory.deploy_huggingface_model(model_name, repo_id, config.HF_TOKEN) + response = ModelFactory.deploy_huggingface_model(model_name, repo_id, hf_token=config.HF_TOKEN) assert response["statusCode"] == 400 assert response["message"] == "err.unable_to_onboard_model" -@pytest.mark.skip(reason="Model Deployment is deactivated for improvements.") +# @pytest.mark.skip(reason="Model Deployment is deactivated for improvements.") def test_gated_model(): # Start the deployment model_name = "Test Model" repo_id = "meta-llama/Llama-2-7b-hf" - response = ModelFactory.deploy_huggingface_model(model_name, repo_id, "mock_key") + response = ModelFactory.deploy_huggingface_model(model_name, repo_id, hf_token="mock_key") assert response["statusCode"] == 400 assert response["message"] == "err.unable_to_onboard_model" diff --git a/tests/image_upload_e2e_test.py b/tests/functional/model/image_upload_e2e_test.py similarity index 72% rename from tests/image_upload_e2e_test.py rename to tests/functional/model/image_upload_e2e_test.py index 0e2ccbc5..7c7efbcc 100644 --- a/tests/image_upload_e2e_test.py +++ b/tests/functional/model/image_upload_e2e_test.py @@ -9,7 +9,6 @@ import pytest -@pytest.mark.skip(reason="Model Upload is deactivated for improvements.") def test_create_and_upload_model(): # List the host machines host_response = ModelFactory.list_host_machines() @@ -31,14 +30,15 @@ def test_create_and_upload_model(): # Register the model, and create an image repository for it. with open(Path("tests/test_requests/create_asset_request.json")) as f: - register_payload = json.load(f) - name = register_payload["name"] - host_machine = register_payload["hostingMachine"] - version = register_payload["version"] - description = register_payload["description"] - function = register_payload["function"] - source_language = register_payload["sourceLanguage"] - register_response = ModelFactory.create_asset_repo(name, host_machine, version, description, function, source_language) + mock_register_payload = json.load(f) + name = mock_register_payload["name"] + description = mock_register_payload["description"] + function = mock_register_payload["function"] + source_language = mock_register_payload["sourceLanguage"] + input_modality = mock_register_payload["input_modality"] + output_modality = mock_register_payload["output_modality"] + documentation_url = mock_register_payload["documentation_url"] + register_response = ModelFactory.create_asset_repo(name, description, function, source_language, input_modality, output_modality, documentation_url, config.TEAM_API_KEY) assert "id" in register_response.keys() assert "repositoryName" in register_response.keys() model_id = register_response["id"] @@ -56,10 +56,7 @@ def test_create_and_upload_model(): registry = login_response["registry"] # Push an image to ECR - # os.system("aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 535945872701.dkr.ecr.us-east-1.amazonaws.com") low_level_client = docker.APIClient(base_url="unix://var/run/docker.sock") - # low_level_client.pull("535945872701.dkr.ecr.us-east-1.amazonaws.com/bash") - # low_level_client.tag("535945872701.dkr.ecr.us-east-1.amazonaws.com/bash", f"{registry}/{repo_name}") low_level_client.pull("bash") low_level_client.tag("bash", f"{registry}/{repo_name}") low_level_client.push(f"{registry}/{repo_name}", auth_config={"username": username, "password": password}) diff --git a/tests/image_upload_functional_test.py b/tests/functional/model/image_upload_functional_test.py similarity index 81% rename from tests/image_upload_functional_test.py rename to tests/functional/model/image_upload_functional_test.py index b9dd3ebf..60d1d3f0 100644 --- a/tests/image_upload_functional_test.py +++ b/tests/functional/model/image_upload_functional_test.py @@ -1,13 +1,12 @@ __author__ = "michaellam" from pathlib import Path import json -from aixplain.utils import config -from tests.test_utils import delete_asset, delete_service_account from aixplain.factories.model_factory import ModelFactory +from tests.test_utils import delete_asset, delete_service_account +from aixplain.utils import config +import docker import pytest - -@pytest.mark.skip(reason="Model Upload is deactivated for improvements.") def test_login(): response = ModelFactory.asset_repo_login() assert response["username"] == "AWS" @@ -18,18 +17,17 @@ def test_login(): delete_service_account(config.TEAM_API_KEY) -@pytest.mark.skip(reason="Model Upload is deactivated for improvements.") def test_create_asset_repo(): with open(Path("tests/test_requests/create_asset_request.json")) as f: mock_register_payload = json.load(f) name = mock_register_payload["name"] - host_machine = mock_register_payload["hostingMachine"] - version = mock_register_payload["version"] description = mock_register_payload["description"] function = mock_register_payload["function"] source_language = mock_register_payload["sourceLanguage"] - response = ModelFactory.create_asset_repo(name, host_machine, version, description, function, source_language) - print(response) + input_modality = mock_register_payload["input_modality"] + output_modality = mock_register_payload["output_modality"] + documentation_url = mock_register_payload["documentation_url"] + response = ModelFactory.create_asset_repo(name, description, function, source_language, input_modality, output_modality, documentation_url, config.TEAM_API_KEY) response_dict = dict(response) assert "id" in response_dict.keys() assert "repositoryName" in response_dict.keys() @@ -38,7 +36,6 @@ def test_create_asset_repo(): delete_asset(response["id"], config.TEAM_API_KEY) -@pytest.mark.skip(reason="Model Upload is deactivated for improvements.") def test_list_host_machines(): response = ModelFactory.list_host_machines() for hosting_machine_dict in response: @@ -49,7 +46,6 @@ def test_list_host_machines(): assert "hourlyCost" in hosting_machine_dict.keys() -@pytest.mark.skip(reason="Model Upload is deactivated for improvements.") def test_get_functions(): # Verbose response = ModelFactory.list_functions(True) diff --git a/tests/functional/pipelines/data/script.py b/tests/functional/pipelines/data/script.py new file mode 100644 index 00000000..3403fa61 --- /dev/null +++ b/tests/functional/pipelines/data/script.py @@ -0,0 +1,51 @@ +__author__ = "thiagocastroferreira" + +import argparse +import json + + +def main(transcripts, speakers, output_file): + # get the speech recognition json + transcripts = json.load(open(transcripts)) + # get the speaker diarization json + speakers = json.load(open(speakers)) + + # build the response + response = [] + for i, transcript in enumerate(transcripts): + merge = { + "transcript": transcript["attributes"]["data"], + "speaker": speakers[i]["attributes"]["data"]["data"], + } + response.append( + { + "index": i, + "success": True, + "input_type": "text", + "is_url": transcript["is_url"], + "details": {}, + "input_segment_info": transcript["input_segment_info"], + "attributes": {"data": merge, "input": merge}, + } + ) + + # save the response, based on the intermediate representation format, in the output_file + with open(output_file, "w") as f: + json.dump(response, f) + + +if __name__ == "__main__": + # Create the parser + parser = argparse.ArgumentParser() + # Add arguments + parser.add_argument("--transcripts", type=str, required=True) + parser.add_argument("--speakers", type=str, required=True) + parser.add_argument("--output_file", type=str, required=True) + # Parse the argument + args = parser.parse_args() + + transcripts = args.transcripts + speakers = args.speakers + output_file = args.output_file + + main(transcripts, speakers, output_file) diff --git a/tests/functional/pipelines/designer_test.py b/tests/functional/pipelines/designer_test.py new file mode 100644 index 00000000..62f42f7e --- /dev/null +++ b/tests/functional/pipelines/designer_test.py @@ -0,0 +1,248 @@ +import pytest + +from aixplain.enums import DataType +from aixplain.factories import PipelineFactory +from aixplain.modules.pipeline.designer import ( + Link, + Operation, + Route, + RouteType, +) +from aixplain.modules import Pipeline +from aixplain.modules.pipeline.designer import AssetNode +from uuid import uuid4 + + +@pytest.fixture +def pipeline(): + # Setup: Initialize the pipeline + pipeline = PipelineFactory.init( + name=str(uuid4()), + ) + + # Yield control back to the test function + yield pipeline + + # Teardown: Ensure the pipeline is deleted + if pipeline is not None: + pipeline.delete() + + +def test_create_asr_pipeline(pipeline): + # add nodes to the pipeline + input = pipeline.input() + model1 = AssetNode(asset_id="60ddefab8d38c51c5885ee38") + pipeline.add_node(model1) + + model2 = AssetNode(asset_id="60ddefd68d38c51c588608f1") + pipeline.add_node(model2) + + # link the nodes + link1 = Link( + from_node=input, + to_node=model1, + from_param="input", + to_param="source_audio", + ) + pipeline.add_link(link1) + + link2 = Link( + from_node=model1, + to_node=model2, + from_param="data", + to_param="text", + ) + pipeline.add_link(link2) + + # use the output of the last node + model1.use_output("data") + model2.use_output("data") + + # save the pipeline as draft + pipeline.save() + + assert isinstance(pipeline, Pipeline) + assert pipeline.id != "" + + +def test_create_mt_pipeline_and_run(pipeline): + # add nodes to the pipeline + input = pipeline.input() + model1 = pipeline.translation(asset_id="60ddef828d38c51c5885d491") + output = pipeline.output() + + # link the nodes + input.link( + to_node=model1, + from_param=input.outputs.input, + to_param=model1.inputs.text, + ) + + # use the output of the last node + model1.link( + to_node=output, + from_param=model1.outputs.data, + to_param=output.inputs.output, + ) + + # save the pipeline as an asset + pipeline.save(save_as_asset=True) + + assert isinstance(pipeline, Pipeline) + assert pipeline.id != "" + + pipeline = PipelineFactory.get(pipeline.id) + + # run the pipeline + output = pipeline.run( + "https://aixplain-platform-assets.s3.amazonaws.com/samples/en/CPAC1x2.txt", + **{"batchmode": False, "version": "2.0"}, + ) + assert output["status"] == "SUCCESS" + + +def test_routing_pipeline(pipeline): + + TRANSLATION_ASSET = "60ddefae8d38c51c5885eff7" + SPEECH_RECOGNITION_ASSET = "621cf3fa6442ef511d2830af" + + input = pipeline.input() + translation = pipeline.asset(TRANSLATION_ASSET) + speech_recognition = pipeline.asset(SPEECH_RECOGNITION_ASSET) + + input.route( + translation.inputs.text, speech_recognition.inputs.source_audio + ) + + translation.use_output("data") + speech_recognition.use_output("data") + + pipeline.save() + + output = pipeline.run("This is a sample text!") + + assert output["status"] == "SUCCESS" + assert output.get("data") is not None + assert len(output["data"]) > 0 + assert output["data"][0].get("segments") is not None + assert len(output["data"][0]["segments"]) > 0 + + +def test_scripting_pipeline(pipeline): + + SPEAKER_DIARIZATION_AUDIO_ASSET = "62fab6ecb39cca09ca5bc365" + SPEECH_RECOGNITION_ASSET = "621cf3fa6442ef511d2830af" + + input = pipeline.input() + + segmentor = pipeline.speaker_diarization_audio( + asset_id=SPEAKER_DIARIZATION_AUDIO_ASSET + ) + + speech_recognition = pipeline.speech_recognition( + asset_id=SPEECH_RECOGNITION_ASSET + ) + + script = pipeline.script( + script_path="tests/functional/pipelines/data/script.py" + ) + script.inputs.create_param(code="transcripts", data_type=DataType.TEXT) + script.inputs.create_param(code="speakers", data_type=DataType.LABEL) + script.outputs.create_param(code="data", data_type=DataType.TEXT) + + input.outputs.input.link(segmentor.inputs.audio) + segmentor.outputs.audio.link(speech_recognition.inputs.source_audio) + segmentor.outputs.data.link(script.inputs.speakers) + speech_recognition.outputs.data.link(script.inputs.transcripts) + + script.use_output("data") + + pipeline.save() + + output = pipeline.run( + "s3://aixplain-platform-assets/samples/en/CPAC1x2.wav", + version="2.0", + ) + + assert output["status"] == "SUCCESS" + assert output.get("data") is not None + assert len(output["data"]) > 0 + assert output["data"][0].get("segments") is not None + assert len(output["data"][0]["segments"]) > 0 + + +def test_decision_pipeline(pipeline): + + SENTIMENT_ANALYSIS_ASSET = "6172874f720b09325cbcdc33" + + input = pipeline.input() + + sentiment_analysis = pipeline.sentiment_analysis( + asset_id=SENTIMENT_ANALYSIS_ASSET + ) + + positive_output = pipeline.output() + negative_output = pipeline.output() + decision_node = pipeline.decision( + routes=[ + Route( + type=RouteType.CHECK_VALUE, + operation=Operation.EQUAL, + value="POSITIVE", + path=[positive_output], + ), + Route( + type=RouteType.CHECK_VALUE, + operation=Operation.DIFFERENT, + value="POSITIVE", + path=[negative_output], + ), + ] + ) + + input.outputs.input.link(sentiment_analysis.inputs.text) + sentiment_analysis.outputs.data.link(decision_node.inputs.comparison) + input.outputs.input.link(decision_node.inputs.passthrough) + decision_node.outputs.input.link(positive_output.inputs.output) + decision_node.outputs.input.link(negative_output.inputs.output) + + pipeline.save() + + output = pipeline.run("I feel so bad today!") + + assert output["status"] == "SUCCESS" + assert output.get("data") is not None + assert len(output["data"]) > 0 + assert output["data"][0].get("segments") is not None + assert len(output["data"][0]["segments"]) > 0 + + +def test_reconstructing_pipeline(pipeline): + input = pipeline.input() + + segmentor = pipeline.speaker_diarization_audio( + asset_id="62fab6ecb39cca09ca5bc365" + ) + + speech_recognition = pipeline.speech_recognition( + asset_id="60ddefab8d38c51c5885ee38" + ) + + reconstructor = pipeline.bare_reconstructor() + + input.outputs.input.link(segmentor.inputs.audio) + segmentor.outputs.audio.link(speech_recognition.inputs.source_audio) + speech_recognition.outputs.data.link(reconstructor.inputs.data) + + reconstructor.use_output("data") + + pipeline.save() + + output = pipeline.run( + "s3://aixplain-platform-assets/samples/en/CPAC1x2.wav", + ) + assert output["status"] == "SUCCESS" + assert output.get("data") is not None + assert len(output["data"]) > 0 + assert output["data"][0].get("segments") is not None + assert len(output["data"][0]["segments"]) > 0 diff --git a/tests/test_requests/create_asset_request.json b/tests/test_requests/create_asset_request.json index 4683e526..688dd33a 100644 --- a/tests/test_requests/create_asset_request.json +++ b/tests/test_requests/create_asset_request.json @@ -1,8 +1,9 @@ { "name": "mock_name", - "hostingMachine": "aix-2c-8g-od", - "version": "mock_version", "description": "mock_description", - "function": "Speech Recognition", - "sourceLanguage": "en" + "function": "Text Generation", + "sourceLanguage": "en", + "input_modality": "text", + "output_modality": "text", + "documentation_url": "" } \ No newline at end of file diff --git a/tests/unit/agent_test.py b/tests/unit/agent_test.py new file mode 100644 index 00000000..680fc21a --- /dev/null +++ b/tests/unit/agent_test.py @@ -0,0 +1,63 @@ +import pytest +import requests_mock +from aixplain.modules import Agent +from aixplain.utils import config + + +def test_fail_no_data_query(): + agent = Agent("123", "Test Agent") + with pytest.raises(Exception) as exc_info: + agent.run_async() + assert str(exc_info.value) == "Either 'data' or 'query' must be provided." + + +def test_fail_query_must_be_provided(): + agent = Agent("123", "Test Agent") + with pytest.raises(Exception) as exc_info: + agent.run_async(data={}) + assert str(exc_info.value) == "When providing a dictionary, 'query' must be provided." + + +def test_fail_query_as_text_when_content_not_empty(): + agent = Agent("123", "Test Agent") + with pytest.raises(Exception) as exc_info: + agent.run_async( + data={"query": "https://aixplain-platform-assets.s3.amazonaws.com/samples/en/CPAC1x2.wav"}, + content=["https://aixplain-platform-assets.s3.amazonaws.com/samples/en/CPAC1x2.wav"], + ) + assert str(exc_info.value) == "When providing 'content', query must be text." + + +def test_fail_content_exceed_maximum(): + agent = Agent("123", "Test Agent") + with pytest.raises(Exception) as exc_info: + agent.run_async( + data={"query": "Transcribe the audios:"}, + content=[ + "https://aixplain-platform-assets.s3.amazonaws.com/samples/en/CPAC1x2.wav", + "https://aixplain-platform-assets.s3.amazonaws.com/samples/en/CPAC1x2.wav", + "https://aixplain-platform-assets.s3.amazonaws.com/samples/en/CPAC1x2.wav", + "https://aixplain-platform-assets.s3.amazonaws.com/samples/en/CPAC1x2.wav", + ], + ) + assert str(exc_info.value) == "The maximum number of content inputs is 3." + + +def test_fail_key_not_found(): + agent = Agent("123", "Test Agent") + with pytest.raises(Exception) as exc_info: + agent.run_async(data={"query": "Translate the text: {{input1}}"}, content={"input2": "Hello, how are you?"}) + assert str(exc_info.value) == "Key 'input2' not found in query." + + +def test_sucess_query_content(): + agent = Agent("123", "Test Agent") + with requests_mock.Mocker() as mock: + url = agent.url + headers = {"x-api-key": config.TEAM_API_KEY, "Content-Type": "application/json"} + ref_response = {"data": "Hello, how are you?", "status": "IN_PROGRESS"} + mock.post(url, headers=headers, json=ref_response) + + response = agent.run_async(data={"query": "Translate the text: {{input1}}"}, content={"input1": "Hello, how are you?"}) + assert response["status"] == ref_response["status"] + assert response["url"] == ref_response["data"] diff --git a/tests/unit/designer_unit_test.py b/tests/unit/designer_unit_test.py new file mode 100644 index 00000000..824fd162 --- /dev/null +++ b/tests/unit/designer_unit_test.py @@ -0,0 +1,667 @@ +import pytest +import unittest.mock as mock + + +from aixplain.enums import DataType +from aixplain.modules.pipeline.designer.base import ( + Node, + Link, + Param, + ParamProxy, + Inputs, + Outputs, + InputParam, + OutputParam, +) + +from aixplain.modules.pipeline.designer.enums import ( + ParamType, + NodeType, +) + +from aixplain.modules.pipeline.designer.mixins import LinkableMixin +from aixplain.modules.pipeline.designer.pipeline import DesignerPipeline + + +def test_create_node(): + + pipeline = DesignerPipeline() + + class BareNode(Node): + pass + + with mock.patch("aixplain.modules.pipeline.designer.Node.attach_to") as mock_attach_to: + node = BareNode(number=3, label="FOO") + mock_attach_to.assert_not_called() + assert isinstance(node.inputs, Inputs) + assert isinstance(node.outputs, Outputs) + assert node.number == 3 + assert node.label == "FOO" + + class FooNodeInputs(Inputs): + pass + + class FooNodeOutputs(Outputs): + pass + + class FooNode(Node[FooNodeInputs, FooNodeOutputs]): + inputs_class = FooNodeInputs + outputs_class = FooNodeOutputs + + with mock.patch("aixplain.modules.pipeline.designer.Node.attach_to") as mock_attach_to: + node = FooNode(pipeline=pipeline, number=3, label="FOO") + mock_attach_to.assert_called_once_with(pipeline) + assert isinstance(node.inputs, FooNodeInputs) + assert isinstance(node.outputs, FooNodeOutputs) + assert node.number == 3 + assert node.label == "FOO" + + +def test_node_attach_to(): + + pipeline = DesignerPipeline() + + class BareNode(Node): + pass + + node = BareNode() + with pytest.raises(AssertionError) as excinfo: + node.attach_to(pipeline) + + assert "Node type not set" in str(excinfo.value) + + class AssetNode(Node): + type: NodeType = NodeType.ASSET + + a = AssetNode() + b = AssetNode() + c = AssetNode() + d = AssetNode(number=8) + e = AssetNode(number=8) + + a.attach_to(pipeline) + b.attach_to(pipeline) + assert b.pipeline is pipeline + assert b.number == 1 + assert b.label == "ASSET(ID=1)" + assert b in pipeline.nodes + assert len(pipeline.nodes) == 2 + + c.attach_to(pipeline) + assert c.pipeline is pipeline + assert c.number == 2 + assert c.label == "ASSET(ID=2)" + assert c in pipeline.nodes + assert len(pipeline.nodes) == 3 + + d.attach_to(pipeline) + assert d.pipeline is pipeline + assert d.number == 8 + assert d.label == "ASSET(ID=8)" + assert d in pipeline.nodes + assert len(pipeline.nodes) == 4 + + with pytest.raises(AssertionError) as excinfo: + e.attach_to(pipeline) + + assert "Node number already exists" in str(excinfo.value) + + +def test_node_serialize(): + pipeline = DesignerPipeline() + + class AssetNode(Node): + type: NodeType = NodeType.ASSET + + node = AssetNode() + + with mock.patch.object(node.inputs, "serialize") as mock_inputs_serialize: + with mock.patch.object(node.outputs, "serialize") as mock_outputs_serialize: + assert node.serialize() == { + "number": node.number, + "type": NodeType.ASSET, + "inputValues": mock_inputs_serialize.return_value, + "outputValues": mock_outputs_serialize.return_value, + "label": node.label, + } + node.attach_to(pipeline) + mock_inputs_serialize.assert_called_once() + mock_outputs_serialize.assert_called_once() + mock_inputs_serialize.reset_mock() + mock_outputs_serialize.reset_mock() + + assert node.serialize() == { + "number": node.number, + "type": NodeType.ASSET, + "inputValues": mock_inputs_serialize.return_value, + "outputValues": mock_outputs_serialize.return_value, + "label": node.label, + } + mock_inputs_serialize.assert_called_once() + mock_outputs_serialize.assert_called_once() + + +def test_create_param(): + class TypedParam(Param): + param_type = ParamType.INPUT + + with mock.patch("aixplain.modules.pipeline.designer.Param.attach_to") as mock_attach_to: + param = TypedParam( + code="param", + data_type=DataType.TEXT, + value="foo", + ) + mock_attach_to.assert_not_called() + + assert param.code == "param" + assert param.data_type == DataType.TEXT + assert param.value == "foo" + assert param.param_type == ParamType.INPUT + + with mock.patch("aixplain.modules.pipeline.designer.Param.attach_to") as mock_attach_to: + param = TypedParam( + code="param", + data_type=DataType.TEXT, + value="foo", + param_type=ParamType.OUTPUT, + ) + mock_attach_to.assert_not_called() + + assert param.code == "param" + assert param.data_type == DataType.TEXT + assert param.value == "foo" + assert param.param_type == ParamType.INPUT + + class UnTypedParam(Param): + pass + + with mock.patch("aixplain.modules.pipeline.designer.Param.attach_to") as mock_attach_to: + param = UnTypedParam( + code="param", + data_type=DataType.TEXT, + value="foo", + param_type=ParamType.OUTPUT, + ) + mock_attach_to.assert_not_called() + + assert param.param_type == ParamType.OUTPUT + + with mock.patch("aixplain.modules.pipeline.designer.Param.attach_to") as mock_attach_to: + param = UnTypedParam( + code="param", + data_type=DataType.TEXT, + value="foo", + param_type=ParamType.INPUT, + ) + mock_attach_to.assert_not_called() + + assert param.param_type == ParamType.INPUT + + class AssetNode(Node): + type: NodeType = NodeType.ASSET + + node = AssetNode() + + with mock.patch("aixplain.modules.pipeline.designer.Param.attach_to") as mock_attach_to: + param = UnTypedParam( + code="param", + data_type=DataType.TEXT, + value="foo", + param_type=ParamType.INPUT, + node=node, + ) + mock_attach_to.assert_called_once_with(node) + + +@pytest.mark.parametrize( + "param_cls, expected_param_type", + [ + (InputParam, ParamType.INPUT), + (OutputParam, ParamType.OUTPUT), + ], +) +def test_create_input_output_param(param_cls, expected_param_type): + class AssetNode(Node): + type: NodeType = NodeType.ASSET + + node = AssetNode() + + with mock.patch("aixplain.modules.pipeline.designer.Param.attach_to") as mock_attach_to: + param = param_cls(code="param", data_type=DataType.TEXT, value="foo", node=node) + mock_attach_to.assert_called_once_with(node) + assert param.code == "param" + assert param.data_type == DataType.TEXT + assert param.value == "foo" + assert param.param_type == expected_param_type + assert not param.node + + +def test_param_attach_to(): + class AssetNode(Node): + type: NodeType = NodeType.ASSET + + node = AssetNode() + + class NoTypeParam(Param): + pass + + param = NoTypeParam(code="param", data_type=DataType.TEXT, value="foo") + with pytest.raises(AssertionError) as excinfo: + param.attach_to(node) + + assert "Param type not set" in str(excinfo.value) + + input = InputParam(code="input", data_type=DataType.TEXT, value="foo") + + with mock.patch.object(node.inputs, "add_param") as mock_add_param: + input.attach_to(node) + mock_add_param.assert_called_once_with(input) + assert input.node is node + + with pytest.raises(AssertionError) as excinfo: + input.attach_to(node) + + assert "Param already attached to a node" in str(excinfo.value) + + output = OutputParam(code="output", data_type=DataType.TEXT, value="bar") + + with mock.patch.object(node.outputs, "add_param") as mock_add_param: + output.attach_to(node) + mock_add_param.assert_called_once_with(output) + assert output.node is node + + +def test_param_link(): + input = InputParam(code="input", data_type=DataType.TEXT, value="foo") + output = OutputParam(code="output", data_type=DataType.TEXT, value="bar") + + with pytest.raises(AssertionError) as excinfo: + output.link(input) + + assert "Param not attached to a node" in str(excinfo.value) + + class AssetNode(Node, LinkableMixin): + type: NodeType = NodeType.ASSET + + a = AssetNode() + b = AssetNode() + + output = OutputParam(code="output", data_type=DataType.TEXT, value="bar") + output.node = a + input = InputParam(code="input", data_type=DataType.TEXT, value="foo") + input.node = b + + with pytest.raises(AssertionError) as excinfo: + input.link(output) + + assert "Invalid param type" in str(excinfo.value) + + with pytest.raises(AssertionError) as excinfo: + output.link(input) + + assert "Param not registered as output" in str(excinfo.value) + + output = OutputParam(code="output", data_type=DataType.TEXT, value="bar", node=a) + input = InputParam(code="input", data_type=DataType.TEXT, value="foo", node=b) + + with mock.patch.object(input, "back_link") as mock_back_link: + output.link(input) + mock_back_link.assert_called_once_with(output) + + +def test_param_back_link(): + input = InputParam(code="input", data_type=DataType.TEXT, value="foo") + output = OutputParam(code="output", data_type=DataType.TEXT, value="bar") + + with pytest.raises(AssertionError) as excinfo: + input.back_link(output) + + assert "Param not attached to a node" in str(excinfo.value) + + class AssetNode(Node, LinkableMixin): + type: NodeType = NodeType.ASSET + + a = AssetNode() + b = AssetNode() + + output = OutputParam(code="output", data_type=DataType.TEXT, value="bar") + output.node = a + input = InputParam(code="input", data_type=DataType.TEXT, value="foo") + input.node = b + + with pytest.raises(AssertionError) as excinfo: + output.back_link(input) + + assert "Invalid param type" in str(excinfo.value) + + with pytest.raises(AssertionError) as excinfo: + input.back_link(output) + + assert "Param not registered as input" in str(excinfo.value) + + output = OutputParam(code="output", data_type=DataType.TEXT, value="bar", node=a) + input = InputParam(code="input", data_type=DataType.TEXT, value="foo", node=b) + + with mock.patch.object(a, "link") as mock_link: + input.back_link(output) + mock_link.assert_called_once_with(b, output, input) + + +def test_create_pipeline(): + pipeline = DesignerPipeline() + + assert pipeline.nodes == [] + assert pipeline.links == [] + assert not pipeline.instance + + +def test_link_create(): + class AssetNode(Node, LinkableMixin): + type: NodeType = NodeType.ASSET + + a = AssetNode() + b = AssetNode() + + with pytest.raises(AssertionError) as excinfo: + link = Link( + from_node=a, + to_node=b, + from_param="output", + to_param="input", + ) + + assert "Invalid from param" in str(excinfo.value) + + a.outputs.create_param("output", DataType.TEXT, "foo") + + with pytest.raises(AssertionError) as excinfo: + link = Link( + from_node=a, + to_node=b, + from_param="output", + to_param="input", + ) + + assert "Invalid to param" in str(excinfo.value) + + b.inputs.create_param("input", DataType.TEXT, "bar") + + link = Link( + from_node=a, + to_node=b, + from_param="output", + to_param="input", + ) + + assert link.from_node == a + assert link.to_node == b + assert link.from_param == "output" + assert link.to_param == "input" + + pipeline = DesignerPipeline() + + with mock.patch("aixplain.modules.pipeline.designer.Link.attach_to") as mock_attach_to: + link = Link( + from_node=a, + to_node=b, + from_param="output", + to_param="input", + pipeline=pipeline, + ) + mock_attach_to.assert_called_once_with(pipeline) + + +def test_link_attach_to(): + + pipeline = DesignerPipeline() + + class AssetNode(Node, LinkableMixin): + type: NodeType = NodeType.ASSET + + a = AssetNode() + b = AssetNode() + + a.outputs.create_param("output", DataType.TEXT, "foo") + b.inputs.create_param("input", DataType.TEXT, "bar") + + link = Link( + from_node=a, + to_node=b, + from_param="output", + to_param="input", + ) + + with mock.patch.object(a, "attach_to") as mock_a_attach_to: + with mock.patch.object(b, "attach_to") as mock_b_attach_to: + link.attach_to(pipeline) + mock_a_attach_to.assert_called_once_with(pipeline) + mock_b_attach_to.assert_called_once_with(pipeline) + assert link.pipeline is pipeline + assert link in pipeline.links + + a = AssetNode(pipeline=pipeline) + b = AssetNode(pipeline=pipeline) + a.outputs.create_param("output", DataType.TEXT, "foo") + b.inputs.create_param("input", DataType.TEXT, "bar") + + link = Link( + from_node=a, + to_node=b, + from_param="output", + to_param="input", + ) + + with mock.patch.object(a, "attach_to") as mock_a_attach_to: + with mock.patch.object(b, "attach_to") as mock_b_attach_to: + link.attach_to(pipeline) + mock_a_attach_to.assert_not_called() + mock_b_attach_to.assert_not_called() + assert link.pipeline is pipeline + assert link in pipeline.links + + with pytest.raises(AssertionError) as excinfo: + link.attach_to(pipeline) + + assert "Link already attached to a pipeline" in str(excinfo.value) + + +def test_link_serialize(): + pipeline = DesignerPipeline() + + class AssetNode(Node, LinkableMixin): + type: NodeType = NodeType.ASSET + + a = AssetNode() + b = AssetNode() + a.outputs.create_param("output", DataType.TEXT, "foo") + b.inputs.create_param("input", DataType.TEXT, "bar") + + link = Link( + from_node=a, + to_node=b, + from_param="output", + to_param="input", + ) + + with pytest.raises(AssertionError) as excinfo: + link.serialize() + + assert "From node number not set" in str(excinfo.value) + a.attach_to(pipeline) + + with pytest.raises(AssertionError) as excinfo: + link.serialize() + + assert "To node number not set" in str(excinfo.value) + b.attach_to(pipeline) + + link = Link( + from_node=a, + to_node=b, + from_param="output", + to_param="input", + ) + + assert link.serialize() == { + "from": a.number, + "to": b.number, + "paramMapping": [ + {"from": "output", "to": "input"}, + ], + } + + +def test_create_param_proxy(): + class AssetNode(Node): + type: NodeType = NodeType.ASSET + + node = AssetNode() + + param_proxy = ParamProxy(node) + assert param_proxy.node is node + assert param_proxy._params == [] + + +def test_param_proxy_add_param(): + class AssetNode(Node): + type: NodeType = NodeType.ASSET + + node = AssetNode() + + param_proxy = ParamProxy(node) + + class FooParam(Param): + pass + + param = FooParam(code="foo", data_type=DataType.TEXT) + param_proxy.add_param(param) + assert param in param_proxy._params + assert hasattr(param_proxy, "foo") + assert param_proxy.foo is param + assert param_proxy.foo.code == "foo" + assert param_proxy.foo.data_type == DataType.TEXT + + with pytest.raises(ValueError) as excinfo: + param_proxy.add_param(param) + + assert "Parameter with code 'foo' already exists." in str(excinfo.value) + + +def test_param_proxy_create_param(): + class AssetNode(Node): + type: NodeType = NodeType.ASSET + + node = AssetNode() + + param_proxy = ParamProxy(node) + + with mock.patch.object(param_proxy, "_create_param") as mock_create_param: + with mock.patch.object(param_proxy, "add_param") as mock_add_param: + param = param_proxy.create_param("foo", DataType.TEXT, "bar", is_required=True) + mock_create_param.assert_called_once_with("foo", DataType.TEXT, "bar") + mock_add_param.assert_called_once_with(param) + assert param.is_required is True + + +def test_param_proxy_attr_access(): + class AssetNode(Node): + type: NodeType = NodeType.ASSET + + node = AssetNode() + + param_proxy = ParamProxy(node) + + class FooParam(Param): + pass + + param = FooParam(code="foo", data_type=DataType.TEXT) + param_proxy.add_param(param) + + assert param in param_proxy + assert "foo" in param_proxy + assert param_proxy["foo"] is param + assert param_proxy.foo is param + + with pytest.raises(KeyError) as excinfo: + param_proxy["bar"] + + assert "'bar'" in str(excinfo.value) + + +def test_node_link(): + class AssetNode(Node, LinkableMixin): + type: NodeType = NodeType.ASSET + + a = AssetNode() + b = AssetNode() + + output = OutputParam(code="output", data_type=DataType.TEXT, value="bar", node=a) + input = InputParam(code="input", data_type=DataType.TEXT, value="foo", node=b) + + # here too lazy to mock Link class properly + # checking the output instance instead + link = a.link(b, from_param=output, to_param=input) + assert isinstance(link, Link) + assert link.from_node == a + assert link.to_node == b + assert link.from_param == "output" + assert link.to_param == "input" + + +def test_pipeline_add_node(): + pipeline = DesignerPipeline() + + class InputNode(Node): + type: NodeType = NodeType.INPUT + + node = InputNode() + pipeline.add_node(node) + assert pipeline.nodes == [node] + assert pipeline.links == [] + + class AssetNode(Node): + type: NodeType = NodeType.ASSET + + node1 = AssetNode() + with mock.patch.object(node1, "attach_to") as mock_attach_to: + pipeline.add_node(node1) + mock_attach_to.assert_called_once_with(pipeline) + + +def test_pipeline_add_nodes(): + pipeline = DesignerPipeline() + + class InputNode(Node): + type: NodeType = NodeType.INPUT + + node = InputNode() + + with mock.patch.object(pipeline, "add_node") as mock_add_node: + pipeline.add_nodes(node) + assert mock_add_node.call_count == 1 + + node1 = InputNode() + node2 = InputNode() + + with mock.patch.object(pipeline, "add_node") as mock_add_node: + pipeline.add_nodes(node1, node2) + assert mock_add_node.call_count == 2 + + +def test_pipeline_add_link(): + pipeline = DesignerPipeline() + + class AssetNode(Node): + type: NodeType = NodeType.ASSET + + a = AssetNode() + a.outputs.create_param("output", DataType.TEXT) + b = AssetNode() + b.inputs.create_param("input", DataType.TEXT) + + link = Link(from_node=a, to_node=b, from_param="output", to_param="input") + pipeline.add_link(link) + + with mock.patch.object(link, "attach_to") as mock_attach_to: + pipeline.add_link(link) + mock_attach_to.assert_called_once_with(pipeline) diff --git a/tests/image_upload_test.py b/tests/unit/image_upload_test.py similarity index 85% rename from tests/image_upload_test.py rename to tests/unit/image_upload_test.py index fb919171..4b192292 100644 --- a/tests/image_upload_test.py +++ b/tests/unit/image_upload_test.py @@ -13,7 +13,6 @@ API_FIXED_HEADER = {"x-api-key": f"{config.TEAM_API_KEY}", "Content-Type": "application/json"} -@pytest.mark.skip(reason="Model Upload is deactivated for improvements.") def test_login(): url = urljoin(config.BACKEND_URL, f"sdk/ecr/login") with requests_mock.Mocker() as mock: @@ -24,24 +23,26 @@ def test_login(): assert creds == mock_json -@pytest.mark.skip(reason="Model Upload is deactivated for improvements.") def test_create_asset_repo(): - url_register = urljoin(config.BACKEND_URL, f"sdk/models/register") + url_register = urljoin(config.BACKEND_URL, f"sdk/models/onboard") url_function = urljoin(config.BACKEND_URL, f"sdk/functions") + print(f"URL_Register {url_register}") with requests_mock.Mocker() as mock: with open(Path("tests/mock_responses/create_asset_repo_response.json")) as f: mock_json_register = json.load(f) - mock.post(url_register, headers=API_FIXED_HEADER, json=mock_json_register) + mock.post(url_register, headers=API_FIXED_HEADER, json=mock_json_register, status_code=201) + with open(Path("tests/mock_responses/list_functions_response.json")) as f: mock_json_functions = json.load(f) mock.get(url_function, headers=AUTH_FIXED_HEADER, json=mock_json_functions) + model_id = ModelFactory.create_asset_repo( - "mock_name", "mock_machines", "mock_version", "mock_description", "Speech Recognition", "en", config.TEAM_API_KEY + "mock_name", "mock_description", "Text Generation", "en", "text", "text", api_key=config.TEAM_API_KEY ) + # print(f"Model ID {model_id}") assert model_id == mock_json_register -@pytest.mark.skip(reason="Model Upload is deactivated for improvements.") def test_list_host_machines(): url = urljoin(config.BACKEND_URL, f"sdk/hosting-machines") with requests_mock.Mocker() as mock: @@ -55,8 +56,6 @@ def test_list_host_machines(): for key in machine_dict.keys(): assert machine_dict[key] == mock_json_dict[key] - -@pytest.mark.skip(reason="Model Upload is deactivated for improvements.") def test_get_functions(): url = urljoin(config.BACKEND_URL, f"sdk/functions") with requests_mock.Mocker() as mock: @@ -66,7 +65,6 @@ def test_get_functions(): functions = ModelFactory.list_functions(config.TEAM_API_KEY) assert functions == mock_json - @pytest.mark.skip(reason="Not currently supported.") def test_list_image_repo_tags(): model_id = "mock_id"