diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 5aae5c5..d9c0304 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.0.0-alpha.13" + ".": "2.0.0-alpha.14" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 7110fa3..14924f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Changelog +## 2.0.0-alpha.14 (2025-07-31) + +Full Changelog: [v2.0.0-alpha.13...v2.0.0-alpha.14](https://github.com/replicate/replicate-python-stainless/compare/v2.0.0-alpha.13...v2.0.0-alpha.14) + +### Features + +* add replicate.use() ([a7b12dd](https://github.com/replicate/replicate-python-stainless/commit/a7b12dd4bcd3a6292b6b06a59047994e408dad59)) +* **client:** support file upload requests ([756cad1](https://github.com/replicate/replicate-python-stainless/commit/756cad11209fa5d3661cb6fb5636660255ca7fbe)) + + +### Chores + +* **docs:** document replicate.run() ([681772d](https://github.com/replicate/replicate-python-stainless/commit/681772de2e0dca70018db9cefafe37277ad0c014)) +* **docs:** document replicate.use() ([b47c9bd](https://github.com/replicate/replicate-python-stainless/commit/b47c9bd42e1d390ca4a652247b1b65a936529017)) +* make the linter happy ([70c1af2](https://github.com/replicate/replicate-python-stainless/commit/70c1af25352ce7033fb834620a48b8aff275ad65)) +* make the mypy happy ([24ddc92](https://github.com/replicate/replicate-python-stainless/commit/24ddc922c5ab2e446fc090f5b5f60b1689712a77)) + ## 2.0.0-alpha.13 (2025-07-25) Full Changelog: [v2.0.0-alpha.12...v2.0.0-alpha.13](https://github.com/replicate/replicate-python-stainless/compare/v2.0.0-alpha.12...v2.0.0-alpha.13) diff --git a/README.md b/README.md index 796ff4c..d4812d4 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,89 @@ we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/) to add `REPLICATE_API_TOKEN="My Bearer Token"` to your `.env` file so that your Bearer Token is not stored in source control. +## Run a model + +You can run a model synchronously using `replicate.run()`: + +```python +import replicate + +output = replicate.run( + "black-forest-labs/flux-schnell", input={"prompt": "astronaut riding a rocket like a horse"} +) +print(output) +``` + +The `run()` method is a convenience function that creates a prediction, waits for it to complete, and returns the output. If you want more control over the prediction process, you can use the lower-level API methods. + +### Handling errors + +`replicate.run()` raises `ModelError` if the prediction fails. You can catch this exception to handle errors gracefully: + +```python +import replicate +from replicate.exceptions import ModelError + +try: + output = replicate.run( + "stability-ai/stable-diffusion-3", input={"prompt": "An astronaut riding a rainbow unicorn"} + ) +except ModelError as e: + print(f"Prediction failed: {e}") + # The prediction object is available as e.prediction + print(f"Prediction ID: {e.prediction.id}") + print(f"Status: {e.prediction.status}") +``` + +### File inputs + +To run a model that takes file inputs, you can pass either a URL to a publicly accessible file or a file handle: + +```python +# Using a URL +output = replicate.run( + "andreasjansson/blip-2:f677695e5e89f8b236e52ecd1d3f01beb44c34606419bcc19345e046d8f786f9", + input={"image": "https://example.com/image.jpg"}, +) + +# Using a local file +with open("path/to/image.jpg", "rb") as f: + output = replicate.run( + "andreasjansson/blip-2:f677695e5e89f8b236e52ecd1d3f01beb44c34606419bcc19345e046d8f786f9", + input={"image": f}, + ) +``` + +### Wait parameter + +By default, `replicate.run()` will wait up to 60 seconds for the prediction to complete. You can configure this timeout: + +```python +# Wait up to 30 seconds +output = replicate.run("...", input={...}, wait=30) + +# Don't wait at all - returns immediately +output = replicate.run("...", input={...}, wait=False) +``` + +When `wait=False`, the method returns immediately after creating the prediction, and you'll need to poll for the result manually. + +## Run a model and stream its output + +For models that support streaming (particularly language models), you can use `replicate.stream()`: + +```python +import replicate + +for event in replicate.stream( + "meta/meta-llama-3-70b-instruct", + input={ + "prompt": "Please write a haiku about llamas.", + }, +): + print(str(event), end="") +``` + ## Async usage Simply import `AsyncReplicate` instead of `Replicate` and use `await` with each API call: @@ -69,6 +152,34 @@ asyncio.run(main()) Functionality between the synchronous and asynchronous clients is otherwise identical. +### Async run() and stream() + +The async client also supports `run()` and `stream()` methods: + +```python +import asyncio +from replicate import AsyncReplicate + +replicate = AsyncReplicate() + + +async def main(): + # Run a model + output = await replicate.run( + "black-forest-labs/flux-schnell", input={"prompt": "astronaut riding a rocket like a horse"} + ) + print(output) + + # Stream a model's output + async for event in replicate.stream( + "meta/meta-llama-3-70b-instruct", input={"prompt": "Write a haiku about coding"} + ): + print(str(event), end="") + + +asyncio.run(main()) +``` + ### With aiohttp By default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend. diff --git a/pyproject.toml b/pyproject.toml index f78296c..c0a2e34 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "replicate" -version = "2.0.0-alpha.13" +version = "2.0.0-alpha.14" description = "The official Python library for the replicate API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/replicate/_base_client.py b/src/replicate/_base_client.py index 3031e5c..d4315ca 100644 --- a/src/replicate/_base_client.py +++ b/src/replicate/_base_client.py @@ -532,7 +532,10 @@ def _build_request( is_body_allowed = options.method.lower() != "get" if is_body_allowed: - kwargs["json"] = json_data if is_given(json_data) else None + if isinstance(json_data, bytes): + kwargs["content"] = json_data + else: + kwargs["json"] = json_data if is_given(json_data) else None kwargs["files"] = files else: headers.pop("Content-Type", None) diff --git a/src/replicate/_files.py b/src/replicate/_files.py index d563518..5837e94 100644 --- a/src/replicate/_files.py +++ b/src/replicate/_files.py @@ -69,12 +69,12 @@ def _transform_file(file: FileTypes) -> HttpxFileTypes: return file if is_tuple_t(file): - return (file[0], _read_file_content(file[1]), *file[2:]) + return (file[0], read_file_content(file[1]), *file[2:]) raise TypeError(f"Expected file types input to be a FileContent type or to be a tuple") -def _read_file_content(file: FileContent) -> HttpxFileContent: +def read_file_content(file: FileContent) -> HttpxFileContent: if isinstance(file, os.PathLike): return pathlib.Path(file).read_bytes() return file @@ -111,12 +111,12 @@ async def _async_transform_file(file: FileTypes) -> HttpxFileTypes: return file if is_tuple_t(file): - return (file[0], await _async_read_file_content(file[1]), *file[2:]) + return (file[0], await async_read_file_content(file[1]), *file[2:]) raise TypeError(f"Expected file types input to be a FileContent type or to be a tuple") -async def _async_read_file_content(file: FileContent) -> HttpxFileContent: +async def async_read_file_content(file: FileContent) -> HttpxFileContent: if isinstance(file, os.PathLike): return await anyio.Path(file).read_bytes() diff --git a/src/replicate/_version.py b/src/replicate/_version.py index 712e08d..03a97df 100644 --- a/src/replicate/_version.py +++ b/src/replicate/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "replicate" -__version__ = "2.0.0-alpha.13" # x-release-please-version +__version__ = "2.0.0-alpha.14" # x-release-please-version