diff --git a/README.md b/README.md index 7d9f4303..849a66b2 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,8 @@ pip install --upgrade together # Usage +> 🚧 You will need to create a free account with [together.ai](https://api.together.xyz/) to obtain a Together API Key. + The Python Library requires your Together API Key to be configured. This key can be found in your Account's settings on the Playground. Simply click on and navigate to Profile Button > Settings > API Keys. The API Key can be configured by either setting the `TOGETHER_API_KEY` environment variable, like this: @@ -25,7 +27,26 @@ import together together.api_key = "xxxxx" ``` -> 🚧 You will need to start a model instance from the Playground before you can query it from the API +Once you've provided your API key, you can browse our list of available models: + +```python +import together + +# set your API key +together.api_key = "xxxxx" + +# list available models and descriptons +models = together.Models.list() + +# print the first model's name +print(models[0]['name']) +``` + +Let's start an instance of one of the models in the list above. You can also start an instance by clicking play on any model in the [models playground](https://api.together.xyz/playground). + +```python +together.Models.start("togethercomputer/RedPajama-INCITE-7B-Base") +``` Once you've started a model instance, you can start querying: @@ -47,6 +68,18 @@ output = together.Complete.create("Space robots", model="togethercomputer/RedPaj print(output['output']['choices'][0]['text']) ``` +Check which models have been started or stopped: + +```python +together.Models.instances() +``` + +To stop your model instance: + +```python +together.Models.stop("togethercomputer/RedPajama-INCITE-7B-Base") +``` + ## Chat The `chat` command is a CLI-based chat application that can be used for back-and-forth conversations with models in a pre-defined format. @@ -88,9 +121,19 @@ together --help # list available models together models list +# start a model +together models start togethercomputer/RedPajama-INCITE-7B-Base + # create completion together complete "Space robots" -m togethercomputer/RedPajama-INCITE-7B-Base + +# check which models are running +together models instances + +# stop a model +together models stop togethercomputer/RedPajama-INCITE-7B-Base ``` + ## Contributing 1. Clone the repo and make your changes 2. Run `pip install together['quality']` diff --git a/src/together/__init__.py b/src/together/__init__.py index fc1b7fae..6f0992e2 100644 --- a/src/together/__init__.py +++ b/src/together/__init__.py @@ -14,6 +14,7 @@ api_base_complete = urllib.parse.urljoin(api_base, "/api/inference") api_base_files = urllib.parse.urljoin(api_base, "/v1/files/") api_base_finetune = urllib.parse.urljoin(api_base, "/v1/fine-tunes/") +api_base_instances = urllib.parse.urljoin(api_base, "instances/") default_text_model = "togethercomputer/RedPajama-INCITE-7B-Chat" default_image_model = "runwayml/stable-diffusion-v1-5" @@ -34,6 +35,7 @@ "api_base_complete", "api_base_files", "api_base_finetune", + "api_base_instances", "default_text_model", "default_image_model", "get_logger", diff --git a/src/together/commands/models.py b/src/together/commands/models.py index 91c5060c..5a66ce20 100644 --- a/src/together/commands/models.py +++ b/src/together/commands/models.py @@ -16,6 +16,9 @@ def add_parser( _add_list(child_parsers) _add_info(child_parsers) + _add_instances(child_parsers) + _add_start(child_parsers) + _add_stop(child_parsers) def _add_list( @@ -50,6 +53,45 @@ def _add_info( subparser.set_defaults(func=_run_info) +def _add_instances( + parser: argparse._SubParsersAction[argparse.ArgumentParser], +) -> None: + subparser = parser.add_parser("instances") + subparser.add_argument( + "--raw", + help="Raw list of instances", + default=False, + action="store_true", + ) + subparser.set_defaults(func=_run_instances) + + +def _add_start( + parser: argparse._SubParsersAction[argparse.ArgumentParser], +) -> None: + subparser = parser.add_parser("start") + subparser.add_argument( + "model", + metavar="MODEL", + help="Proper Model API string name", + type=str, + ) + subparser.set_defaults(func=_run_start) + + +def _add_stop( + parser: argparse._SubParsersAction[argparse.ArgumentParser], +) -> None: + subparser = parser.add_parser("stop") + subparser.add_argument( + "model", + metavar="MODEL", + help="Proper Model API string name", + type=str, + ) + subparser.set_defaults(func=_run_stop) + + def _run_list(args: argparse.Namespace) -> None: models = Models() response = models.list() @@ -87,3 +129,25 @@ def _run_info(args: argparse.Namespace) -> None: model_info = {key: i[key] for key in visible_keys if key in i} print(json.dumps(model_info, indent=4)) break + + +def _run_instances(args: argparse.Namespace) -> None: + models = Models() + response = models.instances() + if args.raw: + print(json.dumps(response, indent=4)) + else: + started_instances = [key for key in response.keys() if response[key] is True] + print(json.dumps(started_instances, indent=4)) + + +def _run_start(args: argparse.Namespace) -> None: + models = Models() + response = models.start(args.model) + print(json.dumps(response, indent=4)) + + +def _run_stop(args: argparse.Namespace) -> None: + models = Models() + response = models.stop(args.model) + print(json.dumps(response, indent=4)) diff --git a/src/together/models.py b/src/together/models.py index 7d030430..e8707966 100644 --- a/src/together/models.py +++ b/src/together/models.py @@ -1,5 +1,5 @@ import urllib.parse -from typing import Any, List +from typing import Any, Dict, List import requests @@ -42,3 +42,87 @@ def list(self) -> List[Any]: raise together.JSONError(e, http_status=response.status_code) return response_list + + @classmethod + def instances(self) -> Dict[str, bool]: + headers = { + "Authorization": f"Bearer {together.api_key}", + "accept": "application/json", + } + try: + response = requests.get( + together.api_base_instances, + headers=headers, + ) + response.raise_for_status() + except requests.exceptions.RequestException as e: + logger.critical(f"Response error raised: {e}") + raise together.ResponseError(e) + + try: + response_dict = response.json() + except Exception as e: + logger.critical( + f"JSON Error raised: {e}\nResponse status code = {response.status_code}" + ) + raise together.JSONError(e, http_status=response.status_code) + + return dict(response_dict) + + @classmethod + def start(self, model: str) -> Dict[str, str]: + model_url = urllib.parse.urljoin( + together.api_base_instances, f"start?model={model}" + ) + headers = { + "Authorization": f"Bearer {together.api_key}", + "accept": "application/json", + } + try: + response = requests.post( + model_url, + headers=headers, + ) + response.raise_for_status() + except requests.exceptions.RequestException as e: + logger.critical(f"Response error raised: {e}") + raise together.ResponseError(e) + + try: + response_dict = response.json() + except Exception as e: + logger.critical( + f"JSON Error raised: {e}\nResponse status code = {response.status_code}" + ) + raise together.JSONError(e, http_status=response.status_code) + + return dict(response_dict) + + @classmethod + def stop(self, model: str) -> Dict[str, str]: + model_url = urllib.parse.urljoin( + together.api_base_instances, f"stop?model={model}" + ) + headers = { + "Authorization": f"Bearer {together.api_key}", + "accept": "application/json", + } + try: + response = requests.post( + model_url, + headers=headers, + ) + response.raise_for_status() + except requests.exceptions.RequestException as e: + logger.critical(f"Response error raised: {e}") + raise together.ResponseError(e) + + try: + response_dict = response.json() + except Exception as e: + logger.critical( + f"JSON Error raised: {e}\nResponse status code = {response.status_code}" + ) + raise together.JSONError(e, http_status=response.status_code) + + return dict(response_dict)