Skip to content
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

Add Outlines #1364

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 26 additions & 36 deletions docs/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,56 +163,46 @@ print(prompt)
# A:
```

### Outlines functions
### `Outline`s

Once you are done experimenting with a prompt and an output structure, it is useful to be able to encapsulate all of these in a single function that can be called from other parts of the program. This is what `outlines.Function` allows you to do:
The `Outline` class allows you to encapsulate a model, a prompt template, and an expected output type into a single callable object. This can be useful for generating structured responses based on a given prompt.

=== "function.py"

```python
from pydantic import BaseModel

import outlines
#### Example

First, define a Pydantic model for the expected output:

@outlines.prompt
def tell_a_joke(topic):
"""Tell me a joke about {{ topic }}."""

class Joke(BaseModel):
setup: str
punchline: str
```python
from pydantic import BaseModel

generate_joke = outlines.Function(
tell_a_joke,
Joke,
"microsoft/Phi-3-mini-4k-instruct"
)
```
class OutputModel(BaseModel):
result: int
```

=== "Call a function"
Next, initialize a model and define a template function:

```python
from .function import generate_joke
```python
from outlines import models

response = generate_joke("baseball")
model = models.transformers("gpt2")

# haha
# Joke(setup='Why was the baseball in a bad mood?', punchline='Because it got hit around a lot.')
```
def template(a: int) -> str:
return f"What is 2 times {a}?"
```

=== "Call a function stored on GitHub"
Now, create an `Outline` instance:

You can load a function that is stored on a repository on GitHub directly from Outlines. Say `Someone` stores a function in `joke.py` at the root of the `TheirRepo` repository:
```python
from outlines.outline import Outline

```python
import outlines
fn = Outline(model, template, OutputModel)
```

joke = outlines.Function.from_github("Someone/TheirRepo/joke")
response = joke("baseball")
```
It make it easier for the community to collaborate on the infinite number of use cases enabled by these models!
You can then call the `Outline` instance with the required arguments:

```python
result = fn(3)
print(result) # Expected output: OutputModel(result=6)
```

## Going further

Expand Down
2 changes: 2 additions & 0 deletions outlines/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from outlines.base import vectorize
from outlines.caching import clear_cache, disable_cache, get_cache
from outlines.function import Function
from outlines.outline import Outline
from outlines.prompts import Prompt, prompt

__all__ = [
Expand All @@ -19,4 +20,5 @@
"Prompt",
"vectorize",
"grammars",
"Outline",
]
12 changes: 12 additions & 0 deletions outlines/function.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import importlib.util
import warnings
from dataclasses import dataclass
from typing import TYPE_CHECKING, Callable, Optional, Tuple, Union

Expand All @@ -20,13 +21,24 @@ class Function:
the function can be called with arguments that will be used to render the
prompt template.

Note:
This class is part of the deprecated 'function' module and will be removed
in a future release (1.0.0).
Please pin your version to <1.0.0 if you need to continue using it.

"""

prompt_template: "Prompt"
schema: Union[str, Callable, object]
model_name: str
generator: Optional["SequenceGenerator"] = None

def __post_init__(self):
warnings.warn(
"The 'function' module is deprecated and will be removed in a future release (1.0.0).",
DeprecationWarning,
)

@classmethod
def from_github(cls, program_path: str, function_name: str = "fn"):
"""Load a function stored on GitHub"""
Expand Down
68 changes: 68 additions & 0 deletions outlines/outline.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import json
from dataclasses import dataclass

import jsonschema
from pydantic import BaseModel

from outlines import generate


@dataclass
class Outline:
"""
Outline is a class that creates a callable object to generate responses
based on a given model, a prompt template (a function that returns a `str`) and an expected output type.

Parameters
----------
model : object
The model to be used for generating responses.
template : function
A function that takes arguments and returns a prompt string.
output_type : type
The expected output type of the generated response.

Examples
--------
from pydantic import BaseModel
from outlines import models, Outline

class OutputModel(BaseModel):
result: int

model = models.transformers("gpt2")

def template(a: int) -> str:
return f"What is 2 times {a}?"

fn = Outline(model, template, OutputModel)

result = fn(3)
print(result) # Expected output: OutputModel(result=6)
"""

def __init__(self, model, template, output_type):
if isinstance(output_type, str):
try:
jsonschema.Draft7Validator.check_schema(json.loads(output_type))
except jsonschema.exceptions.SchemaError as e:
raise TypeError(f"Invalid JSON Schema: {e.message}")
elif not issubclass(output_type, BaseModel):
raise TypeError(
"output_type must be a Pydantic model or a valid JSON Schema string"
)

self.template = template
self.output_type = output_type
self.generator = generate.json(model, output_type)

def __call__(self, *args, **kwargs):
prompt = self.template(*args, **kwargs)
response = self.generator(prompt)
try:
if isinstance(self.output_type, str):
return json.loads(response)
return self.output_type.parse_raw(response)
except (ValueError, SyntaxError):
# If `outlines.generate.json` works as intended, this error should never be raised.
raise ValueError(f"Unable to parse response: {response.strip()}")
133 changes: 0 additions & 133 deletions tests/test_function.py

This file was deleted.

Loading
Loading