-
-
Notifications
You must be signed in to change notification settings - Fork 695
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: Ivan Leo <[email protected]>
- Loading branch information
Showing
29 changed files
with
1,689 additions
and
251 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
--- | ||
authors: | ||
- ivanleomk | ||
- yanomaly | ||
categories: | ||
- Writer SDK | ||
comments: true | ||
date: 2024-11-19 | ||
description: Announcing Writer integration with Instructor for structured outputs and enterprise AI workflows | ||
draft: false | ||
slug: writer-support | ||
tags: | ||
- Writer | ||
- Enterprise AI | ||
- Integrations | ||
--- | ||
|
||
# Structured Outputs with Writer now supported | ||
|
||
We're excited to announce that `instructor` now supports [Writer](https://writer.com)'s enterprise-grade LLMs, including their latest Palmyra X 004 model. This integration enables structured outputs and enterprise AI workflows with Writer's powerful language models. | ||
|
||
## Getting Started | ||
|
||
First, make sure that you've signed up for an account on [Writer](https://writer.com) and obtained an API key. Once you've done so, install `instructor` with Writer support by running `pip install instructor[writer]` in your terminal. | ||
|
||
Make sure to set the `WRITER_API_KEY` environment variable with your Writer API key or pass it as an argument to the `Writer` constructor. | ||
|
||
<!-- more --> | ||
|
||
```python | ||
import instructor | ||
from writerai import Writer | ||
from pydantic import BaseModel | ||
|
||
# Initialize Writer client | ||
client = instructor.from_writer(Writer(api_key="your API key")) | ||
|
||
|
||
class User(BaseModel): | ||
name: str | ||
age: int | ||
|
||
|
||
# Extract structured data | ||
user = client.chat.completions.create( | ||
model="palmyra-x-004", | ||
messages=[{"role": "user", "content": "Extract: John is 30 years old"}], | ||
response_model=User, | ||
) | ||
|
||
print(user) | ||
#> name='John' age=30 | ||
``` | ||
|
||
!!! note | ||
|
||
If you'd like to use the Async version of the Writer client, you can do so by using `instructor.from_writer(AsyncWriter())`. | ||
|
||
We also support streaming with the Writer client using our `create_partial` method. This allows you to process responses incrementally as they arrive. | ||
|
||
This is particularly valuable for maintaining responsive applications and delivering a smooth user experience, especially when dealing with larger responses so that users can see immediate results. | ||
|
||
```python | ||
import instructor | ||
from writerai import Writer | ||
from pydantic import BaseModel | ||
|
||
# Initialize Writer client | ||
client = instructor.from_writer(Writer()) | ||
|
||
|
||
text_block = """ | ||
In our recent online meeting, participants from various backgrounds joined to discuss the upcoming tech conference. The names and contact details of the participants were as follows: | ||
- Name: John Doe, Email: [email protected], Twitter: @TechGuru44 | ||
- Name: Jane Smith, Email: [email protected], Twitter: @DigitalDiva88 | ||
- Name: Alex Johnson, Email: [email protected], Twitter: @CodeMaster2023 | ||
During the meeting, we agreed on several key points. The conference will be held on March 15th, 2024, at the Grand Tech Arena located at 4521 Innovation Drive. Dr. Emily Johnson, a renowned AI researcher, will be our keynote speaker. | ||
The budget for the event is set at $50,000, covering venue costs, speaker fees, and promotional activities. Each participant is expected to contribute an article to the conference blog by February 20th. | ||
A follow-up meetingis scheduled for January 25th at 3 PM GMT to finalize the agenda and confirm the list of speakers. | ||
""" | ||
|
||
|
||
class User(BaseModel): | ||
name: str | ||
email: str | ||
twitter: str | ||
|
||
|
||
class MeetingInfo(BaseModel): | ||
date: str | ||
location: str | ||
budget: int | ||
deadline: str | ||
|
||
|
||
PartialMeetingInfo = instructor.Partial[MeetingInfo] | ||
|
||
|
||
extraction_stream = client.chat.completions.create( | ||
model="palmyra-x-004", | ||
messages=[ | ||
{ | ||
"role": "user", | ||
"content": f"Get the information about the meeting and the users {text_block}", | ||
}, | ||
], | ||
response_model=PartialMeetingInfo, | ||
stream=True, | ||
) # type: ignore | ||
|
||
|
||
for obj in extraction_stream: | ||
print(obj) | ||
#> date='March 15th, 2024' location='' budget=None deadline=None | ||
#> date='March 15th, 2024' location='Grand Tech Arena, 4521 Innovation' budget=None deadline=None | ||
#> date='March 15th, 2024' location='Grand Tech Arena, 4521 Innovation Drive' budget=50000 eadline='February 20th' | ||
``` | ||
|
||
As with all our integrations, `instructor` ships with the ability to automatically retry requests that happen due to schema validation without you having to do anything. | ||
|
||
```python | ||
import instructor | ||
from typing import Annotated | ||
from writerai import Writer | ||
from pydantic import BaseModel, AfterValidator, Field | ||
|
||
#Initialize Writer client | ||
client = instructor.from_writer(Writer()) | ||
|
||
|
||
#Example of model, that may require usage of retries | ||
def uppercase_validator(v): | ||
if v.islower(): | ||
raise ValueError("Name must be in uppercase") | ||
return v | ||
|
||
|
||
class User(BaseModel): | ||
name: Annotated[str, AfterValidator(uppercase_validator)] = Field( | ||
..., description="The name of the user" | ||
) | ||
age: int | ||
|
||
|
||
user = client.chat.completions.create( | ||
model="palmyra-x-004", | ||
messages=[{"role": "user", "content": "Extract: jason is 12"}], | ||
response_model=User, | ||
max_retries=3, | ||
) | ||
|
||
print(user) | ||
#> name='JASON' age=12 | ||
``` | ||
|
||
This was a sneak peek into the things that you can do with Writer and `instructor` - from classification of text to sentimen analysis and more. | ||
|
||
We're excited to see what you build with `instructor` and Writer. If you have any other questions about writer, do check out the [Writer Documentation](https://dev.writer.com/introduction) for the API sdk. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
--- | ||
title: Structured Outputs with Writer | ||
description: Learn how to use Writer for structured outputs using their latest Palmyra-X-004 model for more reliable system outputs | ||
--- | ||
|
||
# Structured Outputs with Writer | ||
|
||
This guide demonstrates how to use Writer for structured outputs using their latest Palmyra-X-004 model for more reliable system outputs. | ||
|
||
You'll need to sign up for an account and get an API key. You can do that [here](https://writer.com). | ||
|
||
```bash | ||
export WRITER_API_KEY=<your-api-key-here> | ||
pip install "instructor[writer]" | ||
``` | ||
|
||
## Palmyra-X-004 | ||
|
||
Writer supports structured outputs with their latest Palmyra-X-004 model that introduces tool calling functionality | ||
|
||
### Sync Example | ||
|
||
```python | ||
import instructor | ||
from writerai import Writer | ||
from pydantic import BaseModel | ||
|
||
# Initialize Writer client | ||
client = instructor.from_writer(Writer(api_key="your API key")) | ||
|
||
|
||
class User(BaseModel): | ||
name: str | ||
age: int | ||
|
||
|
||
# Extract structured data | ||
user = client.chat.completions.create( | ||
model="palmyra-x-004", | ||
messages=[{"role": "user", "content": "Extract: John is 30 years old"}], | ||
response_model=User, | ||
) | ||
|
||
print(user) | ||
#> name='John' age=30 | ||
``` | ||
|
||
### Async Example | ||
|
||
```python | ||
import instructor | ||
from writerai import AsyncWriter | ||
from pydantic import BaseModel | ||
|
||
# Initialize Writer client | ||
client = instructor.from_writer(AsyncWriter()) | ||
|
||
|
||
class User(BaseModel): | ||
name: str | ||
age: int | ||
|
||
|
||
async def extract_user(): | ||
# Extract structured data | ||
user = await client.chat.completions.create( | ||
model="palmyra-x-004", | ||
messages=[{"role": "user", "content": "Extract: John is 30 years old"}], | ||
response_model=User, | ||
) | ||
|
||
print(user) | ||
# > name='John' age=30 | ||
|
||
|
||
if __name__ == "__main__": | ||
import asyncio | ||
|
||
asyncio.run(extract_user()) | ||
``` | ||
|
||
## Nested Objects | ||
|
||
Writer also supports nested objects, which is useful for extracting data from more complex responses. | ||
|
||
```python | ||
import instructor | ||
from writerai import Writer | ||
from pydantic import BaseModel | ||
|
||
# Initialize Writer client | ||
client = instructor.from_writer(Writer()) | ||
|
||
|
||
class Address(BaseModel): | ||
street: str | ||
city: str | ||
country: str | ||
|
||
|
||
class User(BaseModel): | ||
name: str | ||
age: int | ||
addresses: list[Address] | ||
|
||
|
||
# Create structured output with nested objects | ||
user = client.chat.completions.create( | ||
model="palmyra-x-004", | ||
messages=[ | ||
{ | ||
"role": "user", | ||
"content": """ | ||
Extract: Jason is 25 years old. | ||
He lives at 123 Main St, New York, USA | ||
and has a summer house at 456 Beach Rd, Miami, USA | ||
""", | ||
}, | ||
], | ||
response_model=User, | ||
) | ||
print(user) | ||
#> { | ||
#> 'name': 'Jason', | ||
#> 'age': 25, | ||
#> 'addresses': [ | ||
#> { | ||
#> 'street': '123 Main St', | ||
#> 'city': 'New York', | ||
#> 'country': 'USA' | ||
#> }, | ||
#> { | ||
#> 'street': '456 Beach Rd', | ||
#> 'city': 'Miami', | ||
#> 'country': 'USA' | ||
#> } | ||
#> ] | ||
#> } | ||
``` | ||
|
||
## Streaming Support | ||
|
||
Instructor has two main ways that you can use to stream responses out | ||
|
||
1. **Iterables**: These are useful when you'd like to stream a list of objects of the same type (Eg. use structured outputs to extract multiple users) | ||
2. **Partial Streaming**: This is useful when you'd like to stream a single object and you'd like to immediately start processing the response as it comes in. | ||
|
||
We currently support streaming for Writer with native tool for both methods listed above. | ||
|
||
### Partial Streaming | ||
|
||
```python | ||
import instructor | ||
from writerai import Writer | ||
from pydantic import BaseModel | ||
|
||
client = instructor.from_writer(Writer()) | ||
|
||
|
||
class Person(BaseModel): | ||
name: str | ||
age: int | ||
|
||
|
||
resp = client.chat.completions.create_partial( | ||
model="palmyra-x-004", | ||
messages=[ | ||
{ | ||
"role": "user", | ||
"content": "Ivan is 27 and lives in Singapore", | ||
} | ||
], | ||
response_model=Person, | ||
) | ||
|
||
for person in resp: | ||
print(person) | ||
# > name=None age=None | ||
# > name='Ivan' age=None | ||
# > name='Ivan' age=27 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.