Skip to content

Commit 86c5e14

Browse files
authored
Document the FileOutput object in the README (#388)
1 parent a54a786 commit 86c5e14

File tree

1 file changed

+144
-49
lines changed

1 file changed

+144
-49
lines changed

README.md

+144-49
Original file line numberDiff line numberDiff line change
@@ -40,46 +40,7 @@ replacing the model identifier and input with your own:
4040
input={"prompt": "a 19th century portrait of a wombat gentleman"}
4141
)
4242

43-
['https://replicate.com/api/models/stability-ai/stable-diffusion/files/50fcac81-865d-499e-81ac-49de0cb79264/out-0.png']
44-
```
45-
46-
> [!TIP]
47-
> You can also use the Replicate client asynchronously by prepending `async_` to the method name.
48-
>
49-
> Here's an example of how to run several predictions concurrently and wait for them all to complete:
50-
>
51-
> ```python
52-
> import asyncio
53-
> import replicate
54-
>
55-
> # https://replicate.com/stability-ai/sdxl
56-
> model_version = "stability-ai/sdxl:39ed52f2a78e934b3ba6e2a89f5b1c712de7dfea535525255b1aa35c5565e08b"
57-
> prompts = [
58-
> f"A chariot pulled by a team of {count} rainbow unicorns"
59-
> for count in ["two", "four", "six", "eight"]
60-
> ]
61-
>
62-
> async with asyncio.TaskGroup() as tg:
63-
> tasks = [
64-
> tg.create_task(replicate.async_run(model_version, input={"prompt": prompt}))
65-
> for prompt in prompts
66-
> ]
67-
>
68-
> results = await asyncio.gather(*tasks)
69-
> print(results)
70-
> ```
71-
72-
To run a model that takes a file input you can pass either
73-
a URL to a publicly accessible file on the Internet
74-
or a handle to a file on your local device.
75-
76-
```python
77-
>>> output = replicate.run(
78-
"andreasjansson/blip-2:f677695e5e89f8b236e52ecd1d3f01beb44c34606419bcc19345e046d8f786f9",
79-
input={ "image": open("path/to/mystery.jpg") }
80-
)
81-
82-
"an astronaut riding a horse"
43+
[<replicate.helpers.FileOutput object at 0x107179b50>]
8344
```
8445

8546
`replicate.run` raises `ModelError` if the prediction fails.
@@ -99,6 +60,55 @@ except ModelError as e
9960
print("Failed prediction: " + e.prediction.id)
10061
```
10162

63+
> [!NOTE]
64+
> By default the Replicate client will hold the connection open for up to 60 seconds while waiting
65+
> for the prediction to complete. This is designed to optimize getting the model output back to the
66+
> client as quickly as possible. For models that output files the file data will be inlined into
67+
> the response as a data-uri.
68+
>
69+
> The timeout can be configured by passing `wait=x` to `replicate.run()` where `x` is a timeout
70+
> in seconds between 1 and 60. To disable the sync mode and the data-uri response you can pass
71+
> `wait=False` to `replicate.run()`.
72+
73+
## AsyncIO support
74+
75+
You can also use the Replicate client asynchronously by prepending `async_` to the method name.
76+
77+
Here's an example of how to run several predictions concurrently and wait for them all to complete:
78+
79+
```python
80+
import asyncio
81+
import replicate
82+
83+
# https://replicate.com/stability-ai/sdxl
84+
model_version = "stability-ai/sdxl:39ed52f2a78e934b3ba6e2a89f5b1c712de7dfea535525255b1aa35c5565e08b"
85+
prompts = [
86+
f"A chariot pulled by a team of {count} rainbow unicorns"
87+
for count in ["two", "four", "six", "eight"]
88+
]
89+
90+
async with asyncio.TaskGroup() as tg:
91+
tasks = [
92+
tg.create_task(replicate.async_run(model_version, input={"prompt": prompt}))
93+
for prompt in prompts
94+
]
95+
96+
results = await asyncio.gather(*tasks)
97+
print(results)
98+
```
99+
100+
To run a model that takes a file input you can pass either
101+
a URL to a publicly accessible file on the Internet
102+
or a handle to a file on your local device.
103+
104+
```python
105+
>>> output = replicate.run(
106+
"andreasjansson/blip-2:f677695e5e89f8b236e52ecd1d3f01beb44c34606419bcc19345e046d8f786f9",
107+
input={ "image": open("path/to/mystery.jpg") }
108+
)
109+
110+
"an astronaut riding a horse"
111+
```
102112

103113
## Run a model and stream its output
104114

@@ -176,7 +186,7 @@ iteration: 30, render:loss: -1.3994140625
176186
'succeeded'
177187

178188
>>> prediction.output
179-
'https://.../output.png'
189+
<replicate.helpers.FileOutput object at 0x107179b50>
180190
```
181191

182192
## Run a model in the background and get a webhook
@@ -217,8 +227,9 @@ iterator = replicate.run(
217227
input={"prompts": "san francisco sunset"}
218228
)
219229

220-
for image in iterator:
221-
display(image)
230+
for index, image in enumerate(iterator):
231+
with open(f"file_{index}.png", "wb") as file:
232+
file.write(image.read())
222233
```
223234

224235
## Cancel a prediction
@@ -263,20 +274,104 @@ if page1.next:
263274

264275
## Load output files
265276

266-
Output files are returned as HTTPS URLs. You can load an output file as a buffer:
277+
Output files are returned as `FileOutput` objects:
267278

268279
```python
269280
import replicate
270-
from PIL import Image
271-
from urllib.request import urlretrieve
281+
from PIL import Image # pip install pillow
272282

273-
out = replicate.run(
283+
output = replicate.run(
274284
"stability-ai/stable-diffusion:27b93a2413e7f36cd83da926f3656280b2931564ff050bf9575f1fdf9bcd7478",
275285
input={"prompt": "wavy colorful abstract patterns, oceans"}
276286
)
277287

278-
urlretrieve(out[0], "/tmp/out.png")
279-
background = Image.open("/tmp/out.png")
288+
# This has a .read() method that returns the binary data.
289+
with open("my_output.png", "wb") as file:
290+
file.write(output[0].read())
291+
292+
# It also implements the iterator protocol to stream the data.
293+
background = Image.open(output[0])
294+
```
295+
296+
### FileOutput
297+
298+
Is a file-like object returned from the `replicate.run()` method that makes it easier to work with models
299+
that output files. It implements `Iterator` and `AsyncIterator` for reading the file data in chunks as well
300+
as `read` and `aread()` to read the entire file into memory.
301+
302+
Lastly, the underlying datasource is available on the `url` attribute.
303+
304+
> [!NOTE]
305+
> The `url` attribute can vary between a remote URL and a data-uri depending on whether the server has
306+
> optimized the request. For small files <5mb using the syncronous API data-uris will be returned to
307+
> remove the need to make subsequent requests for the file data. To disable this pass `wait=false`
308+
> to the replicate.run() function.
309+
310+
To access the file URL:
311+
312+
```python
313+
print(output.url) #=> "data:image/png;base64,xyz123..." or "https://delivery.replicate.com/..."
314+
```
315+
316+
To consume the file directly:
317+
318+
```python
319+
with open('output.bin', 'wb') as file:
320+
file.write(output.read())
321+
```
322+
323+
Or for very large files they can be streamed:
324+
325+
```python
326+
with open(file_path, 'wb') as file:
327+
for chunk in output:
328+
file.write(chunk)
329+
```
330+
331+
Each of these methods has an equivalent `asyncio` API.
332+
333+
```python
334+
async with aiofiles.open(filename, 'w') as file:
335+
await file.write(await output.aread())
336+
337+
async with aiofiles.open(filename, 'w') as file:
338+
await for chunk in output:
339+
await file.write(chunk)
340+
```
341+
342+
For streaming responses from common frameworks, all support taking `Iterator` types:
343+
344+
**Django**
345+
346+
```python
347+
@condition(etag_func=None)
348+
def stream_response(request):
349+
output = replicate.run("black-forest-labs/flux-schnell", input={...}, use_file_output =True)
350+
return HttpResponse(output, content_type='image/webp')
351+
```
352+
353+
**FastAPI**
354+
355+
```python
356+
@app.get("/")
357+
async def main():
358+
output = replicate.run("black-forest-labs/flux-schnell", input={...}, use_file_output =True)
359+
return StreamingResponse(output)
360+
```
361+
362+
**Flask**
363+
364+
```python
365+
@app.route('/stream')
366+
def streamed_response():
367+
output = replicate.run("black-forest-labs/flux-schnell", input={...}, use_file_output =True)
368+
return app.response_class(stream_with_context(output))
369+
```
370+
371+
You can opt out of `FileOutput` by passing `use_file_output=False` to the `replicate.run()` method.
372+
373+
```python
374+
const replicate = replicate.run("acmecorp/acme-model", use_file_output=False);
280375
```
281376

282377
## List models

0 commit comments

Comments
 (0)