Skip to content

Commit

Permalink
update deps
Browse files Browse the repository at this point in the history
  • Loading branch information
aj-ya committed Mar 11, 2024
1 parent 2f3e261 commit 88fbfb8
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 104 deletions.
203 changes: 114 additions & 89 deletions outpostcli/endpoints.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
import json
import os
from typing import Optional
from typing import List, Optional
from urllib.parse import urlparse

import click
from outpostkit import Client, Endpoint, Endpoints
from outpostkit._types.endpoint import (
EndpointAutogeneratedHFModelDetails,
EndpointAutogeneratedOutpostModelDetails,
EndpointAutogeneratedTemplateConfig,
EndpointCustomTemplateConfig,
EndpointPrebuiltContainerDetails,
EndpointSecret,
ReplicaScalingConfig,
)
from outpostkit.exceptions import OutpostError
from outpostkit.utils import convert_outpost_date_str_to_date
from rich.table import Table

Expand All @@ -13,7 +23,7 @@
add_options,
api_token_opt,
click_group,
combine_inf_load_source_model,
condense_endpt_autogen_configs,
console,
entity_opt,
)
Expand Down Expand Up @@ -45,8 +55,10 @@ def list_endpoints(api_token, entity):
for inf in infs_resp.endpoints:
inf_table.add_row(
inf.name,
combine_inf_load_source_model(
inf.loadModelWeightsFrom, inf.outpostModel, inf.huggingfaceModel
(
condense_endpt_autogen_configs(inf.autogeneratedTemplateConfig)
if inf.autogeneratedTemplateConfig is not None
else "custom"
),
inf.status,
inf.hardwareInstance.name,
Expand All @@ -72,14 +84,7 @@ def list_endpoints(api_token, entity):
type=str,
default=None,
required=False,
help="revision of the model to use.",
)
@click.option(
"--huggingface-token-id",
type=str,
default=None,
required=False,
help="revision of the model to use.",
help="huggingface token id to connect private models.",
)
@click.option(
"--hardware-instance",
Expand All @@ -104,14 +109,11 @@ def list_endpoints(api_token, entity):
required=False,
)
@click.option(
"--base-image",
"--prebuilt-container",
type=click.Choice(
[
"transformers-pt",
"transformers-tf",
"transformers",
"python",
"diffusers-pt",
"diffusers-tf",
"tensorflow",
"diffusers",
]
Expand All @@ -120,6 +122,12 @@ def list_endpoints(api_token, entity):
help="base image",
required=False,
)
@click.option(
"--prebuilt-container-config",
type=str,
help="prebuilt container config (JSON)",
required=False,
)
@click.option(
"--visibility",
type=click.Choice(["private", "public", "internal"]),
Expand All @@ -135,6 +143,16 @@ def list_endpoints(api_token, entity):
help="minimum number of replicas",
required=False,
)
@click.option(
"--secret",
"--env",
"-e",
type=str,
multiple=True,
default=None,
help="minimum number of replicas",
required=False,
)
@click.option(
"--replica-scaling-max",
type=int,
Expand Down Expand Up @@ -163,7 +181,6 @@ def create_endpoint(
model_data: Optional[str],
hardware_instance: str,
huggingface_token_id,
base_image: Optional[str],
name: Optional[str],
template_path: Optional[str],
task_type: str,
Expand All @@ -172,6 +189,9 @@ def create_endpoint(
visibility: str,
replica_scaling_scaledown_period: int,
replica_scaling_target_pending_req: int,
prebuilt_container: Optional[str],
prebuilt_container_config: Optional[str],
secret: Optional[List[str]],
):
client = Client(api_token=api_token)
if template_path:
Expand All @@ -181,58 +201,56 @@ def create_endpoint(
"Please specify the template classname along with the path.", err=True
)
return
if not base_image:
if not prebuilt_container:
click.echo("Please specify the base image you want to use.", err=True)
return
try:
result = urlparse(actual_path)
if all([result.scheme, result.netloc]):
data = {
"templateType": "custom",
"customTemplateConfig": {
"className": class_name,
"url": actual_path,
},
"hardwareInstance": hardware_instance,
"taskType": task_type,
"name": name,
"containerType": "prebuilt",
"visibility": visibility,
"prebuiltImageName": base_image,
"replicaScalingConfig": {
"min": replica_scaling_min,
"max": replica_scaling_max,
"scaledownPeriod": replica_scaling_scaledown_period,
"targetPendingRequests": replica_scaling_target_pending_req,
},
}
create_resp = Endpoints(client=client, entity=entity).create(json=data)
custom_template_config = EndpointCustomTemplateConfig(type="url",path=actual_path, className=class_name)
config = None
try:
config = json.loads(prebuilt_container_config)
except json.JSONDecodeError as e:
raise OutpostError(f"Invalid JSON: prebuilt_container_config: {str(e)}") from e
prebuilt_container_details = EndpointPrebuiltContainerDetails(name=prebuilt_container, config=config)
replica_scaling_config= ReplicaScalingConfig(
min= replica_scaling_min,
max= replica_scaling_max,
scaledownPeriod= replica_scaling_scaledown_period,
targetPendingRequests= replica_scaling_target_pending_req,
)
secrets = None
if(secret is not None):
secrets = []
for s in secret:
name,value = s.split('=',maxsplit=1)
if(name =='' or value ==''):
raise OutpostError(f"Invalid secret config: {"name" if name =='' else "value"} empty")
secrets.append(EndpointSecret(name=name,value=value))
create_resp = Endpoints(client=client, entity=entity).create(template=custom_template_config, container=prebuilt_container_details, hardware_instance=hardware_instance, task_type=task_type, name=name,visibility=visibility, replica_scaling_config=replica_scaling_config, secrets=secrets)
else:
raise ValueError("Not an url.")
except ValueError:
if os.path.exists(actual_path) and os.path.isfile(actual_path):
data = {
"templateType": "custom",
"customTemplateConfig": {
"className": class_name,
},
"taskType": task_type,
"name": name,
"containerType": "prebuilt",
"visibility": visibility,
"hardwareInstance": hardware_instance,
"prebuiltImageName": base_image,
"replicaScalingConfig": {
"min": replica_scaling_min,
"max": replica_scaling_max,
"scaledownPeriod": replica_scaling_scaledown_period,
"targetPendingRequests": replica_scaling_target_pending_req,
},
}
create_resp = Endpoints(client=client, entity=entity).create(
data={"metadata": json.dumps(data)},
files={"template": open(actual_path, mode="rb")},
custom_template_config = EndpointCustomTemplateConfig(type="file",path=actual_path, className=class_name)
prebuilt_container_details = EndpointPrebuiltContainerDetails(name=prebuilt_container, config=config)
replica_scaling_config= ReplicaScalingConfig(
min= replica_scaling_min,
max= replica_scaling_max,
scaledownPeriod= replica_scaling_scaledown_period,
targetPendingRequests= replica_scaling_target_pending_req,
)
secrets = None
if(secret is not None):
secrets = []
for s in secret:
name,value = s.split('=',maxsplit=1)
if(name =='' or value ==''):
raise OutpostError(f"Invalid secret config: {"name" if name =='' else "value"} empty") from None
secrets.append(EndpointSecret(name=name,value=value))

create_resp = Endpoints(client=client, entity=entity).create(template=custom_template_config, container=prebuilt_container_details, hardware_instance=hardware_instance, task_type=task_type, name=name,visibility=visibility, replica_scaling_config=replica_scaling_config, secrets=secrets)
else:
click.echo("Invalid template file path.", err=True)
return
Expand All @@ -245,41 +263,39 @@ def create_endpoint(
click.echo("Please provided the model name.", err=True)
return
m_splits = model_data.split(":", 1)
model_details: dict[str] = None
template_config = None
if len(m_splits) == 1:
[model_name, revision] = model_data.split("@", 1)
model_details = {
"modelSource": "outpost",
"outpostModel": {"fullName": model_name, "commit": revision},
}
template_config = EndpointAutogeneratedTemplateConfig(modelSource= "outpost",
outpostModel= EndpointAutogeneratedOutpostModelDetails(fullName= model_name),
revision=revision
)
else:
if m_splits[0] == "hf" or m_splits[0] == "huggingface":
[model_name, revision] = model_data.split("@", 1)
model_details = {
"modelSource": "huggingface",
"huggingfaceModel": {
"id": model_name,
"revision": revision,
"keyId": huggingface_token_id,
},
}
template_config = EndpointAutogeneratedTemplateConfig(modelSource= 'huggingface',
outpostModel= EndpointAutogeneratedHFModelDetails(id= model_name,keyId=huggingface_token_id),
revision=revision
)
else:
raise SourceNotSupportedError(f"source {m_splits[0]} not supported.")
prebuilt_container_details = EndpointPrebuiltContainerDetails(name=prebuilt_container, config=config) if prebuilt_container else None
replica_scaling_config= ReplicaScalingConfig(
min= replica_scaling_min,
max= replica_scaling_max,
scaledownPeriod= replica_scaling_scaledown_period,
targetPendingRequests= replica_scaling_target_pending_req,
)
secrets = None
if(secret is not None):
secrets = []
for s in secret:
name,value = s.split('=',maxsplit=1)
if(name =='' or value ==''):
raise OutpostError(f"Invalid secret config: {"name" if name =='' else "value"} empty") from None
secrets.append(EndpointSecret(name=name,value=value))

create_body = {
"templateType": "autogenerated",
"autogeneratedTemplateConfig": model_details,
"hardwareInstance": hardware_instance,
"visibility": visibility,
"name": name,
"replicaScalingConfig": {
"min": replica_scaling_min,
"max": replica_scaling_max,
"scaledownPeriod": replica_scaling_scaledown_period,
"targetPendingRequests": replica_scaling_target_pending_req,
},
}
create_resp = Endpoints(client=client, entity=entity).create(json=create_body)
create_resp = Endpoints(client=client, entity=entity).create(template=template_config, container=prebuilt_container_details, hardware_instance=hardware_instance, task_type=task_type, name=name,visibility=visibility, replica_scaling_config=replica_scaling_config, secrets=secrets)
click.echo("endpoint created...")
click.echo(f"name: {create_resp.name}")
click.echo(f"id: {create_resp.id}")
Expand Down Expand Up @@ -350,11 +366,20 @@ def delete_endpoint(api_token, entity, name):
return "Aborted"


@endpoints.command(name="status")
@endpoints.command(name="replica-status")
@click.argument("name", type=str, nargs=1)
@add_options([api_token_opt, entity_opt])
@click.option("--verbose", "-v", is_flag=True, help="Verbose")
def inf_dep_status(api_token, entity, name):
client = Client(api_token=api_token)
status_data = Endpoint(
client=client, api_token=api_token, name=name, entity=entity
).replica_status()
click.echo(status_data)

@endpoints.command(name="status")
@click.argument("name", type=str, nargs=1)
@add_options([api_token_opt, entity_opt])
def inf_status(api_token, entity, name):
client = Client(api_token=api_token)
status_data = Endpoint(
client=client, api_token=api_token, name=name, entity=entity
Expand Down
38 changes: 25 additions & 13 deletions outpostcli/utils.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
from typing import Optional

import click
from outpostkit._types.endpoint import (
EndpointAutogeneratedHFModelDetails,
EndpointAutogeneratedOutpostModelDetails,
)
from outpostkit._types.endpoint import EndpointAutogeneratedTemplateConfigDetails
from rich.console import Console

from outpostcli.config_utils import (
Expand Down Expand Up @@ -58,17 +55,32 @@ def check_token(token: str):
return -1, None


def combine_inf_load_source_model(
load_source,
outpost_model: Optional[EndpointAutogeneratedOutpostModelDetails],
hf_model: Optional[EndpointAutogeneratedHFModelDetails],
def condense_endpt_autogen_configs(
autogen_configs: EndpointAutogeneratedTemplateConfigDetails,
):
if load_source == "hugginface" and hf_model:
return f"hf:{hf_model.id}"
elif load_source == "outpost" and outpost_model:
return f"{outpost_model.model.fullName}"
load_source = autogen_configs.modelSource
revision = (
f"@{autogen_configs.revision}" if autogen_configs.revision is not None else ""
)
if load_source == "hugginface":
gen_str: str = "hf:"
hf_model = autogen_configs.huggingfaceModel
if hf_model:
gen_str = gen_str + hf_model.id
else:
gen_str = gen_str + "<unknown>"
return f"{gen_str}{revision}"

if load_source == "outpost":
gen_str: str = ""
op_model = autogen_configs.outpostModel
if hf_model:
gen_str = op_model
else:
gen_str = "<unknown>"
return f"{gen_str}:{revision}"
else:
return "custom"
return "cannot-parse-model"


def add_options(options):
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ license = { file = "LICENSE" }
authors = [{ name = "Outpost Innovations, Inc." }]
requires-python = ">=3.8"
dependencies = [
"outpostkit>=0.0.34",
"outpostkit>=0.0.44",
"click",
"rich",
]
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ markdown-it-py==3.0.0
# via rich
mdurl==0.1.2
# via markdown-it-py
outpostkit==0.0.34
outpostkit==0.0.44
# via outpostcli (pyproject.toml)
packaging==23.2
# via outpostkit
Expand Down

0 comments on commit 88fbfb8

Please sign in to comment.