-
Notifications
You must be signed in to change notification settings - Fork 249
Add experimental replicate.use()
function
#438
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 18 commits
e4398b9
587ed82
70e1da7
607150f
736604b
40c97a7
196aef0
9a293e6
83d8fad
f017857
35eb88b
8d85629
20a37d1
bae5dc8
ae1589f
82e40ce
bad0ce4
35e66dc
639f234
65a89d3
b79a5cd
80ce4e5
bc5d7d8
4111e82
e8acdb2
2df34ed
c982d53
050798e
a00b5d2
83793a0
2afd364
dd64e91
cd12cf4
1185b7b
f160fef
57bab3e
adb4fa7
3b5200b
3fb2024
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -503,6 +503,106 @@ replicate = Client( | |
> Never hardcode authentication credentials like API tokens into your code. | ||
> Instead, pass them as environment variables when running your program. | ||
|
||
## Experimental `use()` interface | ||
|
||
The latest versions of `replicate >= 1.0.8` include a new experimental `use()` function that is intended to make running a model closer to calling a function rather than an API request. | ||
|
||
Some key differences to `replicate.run()`. | ||
|
||
1. You "import" the model using the `use()` syntax, after that you call the model like a function. | ||
2. The output type matches the model definition. i.e. if the model uses an iterator output will be an iterator. | ||
3. Files will be downloaded output as `Path` objects*. | ||
|
||
> [!NOTE] | ||
|
||
\* We've replaced the `FileOutput` implementation with `Path` objects. However to avoid unnecessary downloading of files until they are needed we've implemented a `PathProxy` class that will defer the download until the first time the object is used. If you need the underlying URL of the `Path` object you can use the `get_path_url(path: Path) -> str` helper. | ||
|
||
### Examples | ||
|
||
To use a model: | ||
|
||
> [!IMPORTANT] | ||
> For now `use()` MUST be called in the top level module scope. We may relax this in future. | ||
|
||
```py | ||
from replicate import use | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Subtle ergonomic thing, but my instinct would be to call import replicate
flux_dev = replicate.use("black-forest-labs/flux-dev") There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Intention is that both would work. I went with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've updated the README to use the |
||
|
||
flux_dev = use("black-forest-labs/flux-dev") | ||
outputs = flux_dev(prompt="a cat wearing an amusing hat") | ||
|
||
for output in outputs: | ||
print(output) # Path(/tmp/output.webp) | ||
``` | ||
|
||
Models that output iterators will return iterators: | ||
|
||
|
||
```py | ||
claude = use("anthropic/claude-4-sonnet") | ||
|
||
output = claude(prompt="Give me a recipe for tasty smashed avocado on sourdough toast that could feed all of California.") | ||
|
||
for token in output: | ||
print(token) # "Here's a recipe" | ||
``` | ||
|
||
You can call `str()` on a language model to get the full output when done rather than iterating over tokens: | ||
|
||
```py | ||
str(output) # "Here's a recipe to feed all of California (about 39 million people)! ..." | ||
``` | ||
|
||
You can pass the results of one model directly into another: | ||
|
||
```py | ||
from replicate import use | ||
|
||
flux_dev = use("black-forest-labs/flux-dev") | ||
claude = use("anthropic/claude-4-sonnet") | ||
|
||
images = flux_dev(prompt="a cat wearing an amusing hat") | ||
|
||
result = claude(prompt="describe this image for me", image=images[0]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When I pass There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, file outputs are now a thin wrapper around To get the underlying URL, there is a This is then used internally so that the file is never downloaded in cases like this where an output is just passed as an input to another model. Feedback on this would be greatly appreciated. This and the |
||
|
||
print(str(result)) # "This shows an image of a cat wearing a hat ..." | ||
``` | ||
|
||
To create an individual prediction that has not yet resolved, use the `create()` method: | ||
|
||
``` | ||
claude = use("anthropic/claude-4-sonnet") | ||
|
||
prediction = claude.create(prompt="Give me a recipe for tasty smashed avocado on sourdough toast that could feed all of California.") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
☝🏼 I like it! |
||
|
||
prediction.logs() # get current logs (WIP) | ||
|
||
prediction.output() # get the output | ||
``` | ||
|
||
You can access the underlying URL for a Path object returned from a model call by using the `get_path_url()` helper. | ||
|
||
```py | ||
from replicate import use | ||
from replicate.use import get_url_path | ||
|
||
flux_dev = use("black-forest-labs/flux-dev") | ||
outputs = flux_dev(prompt="a cat wearing an amusing hat") | ||
|
||
for output in outputs: | ||
print(get_url_path(output)) # "https://replicate.delivery/xyz" | ||
``` | ||
|
||
### TODO | ||
|
||
There are several key things still outstanding: | ||
|
||
1. Support for asyncio. | ||
2. Support for typing the return value. | ||
3. Support for streaming text when available (rather than polling) | ||
4. Support for streaming files when available (rather than polling) | ||
5. Support for cleaning up downloaded files. | ||
6. Support for streaming logs using `OutputIterator`. | ||
|
||
## Development | ||
|
||
See [CONTRIBUTING.md](CONTRIBUTING.md) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels similar to the FileOutput situation from before, mainly in that it requires explanation to understand, and it feels like a kind of non-standard behavior that docs-skimming users and LLMs won't be able to accurately guess at.
What would feel like the most intuitive thing to an end user?
Am I correct in thinking that this "defer until accessed" downloading behavior and the
get_path_url
feature are two entirely separate concerns? If so, maybe they should be documented separately to avoid confusion.Here's a crack at that:
Downloading output files
Output files are return as Python
Path
objects. However to avoid unnecessary downloading of output files until they are needed, we wrap them in aPathProxy
class that will defer the download until the first time the object is used.Here's an example of how to download outputs to disk:
Accessing outputs as HTTPS URLs
All output files are automatically uploaded to Replicate's CDN, where they are available as HTTPS URLs for up to one hour before expiring.
To access the HTTPS URLs of your output files, use the
get_path_url
helper method:A few other thing come to mind:
get_url_path
, and other placesget_path_url
-- If we're using that, I thinkget_path_url
probably make more sense, as you're "getting the URL for the given Path™"use
... I guess it helps to make it explicit as a helper method that you have to import. Otherwise it would be just a non-standard and undiscoverable mysterious method on the Path instance...There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great feedback thank you. Agree with both of the latter bullets, and the docs suggestions are much better.
The
PathProxy
is definitely similar toFileOutput
, but without the completely new interface. I could be convinced to drop it from the version iteration, but I'd love to solve the issue.Some other things I considered.
.ensure()
method, which is weird if the file doesn't exist yet.Path
at all and just using URLs and having that part of the API diverge from cog.