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

Migrate from Poetry to UV #1216

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
9b16a21
docs: Update integration docs to recommend UV package manager
devin-ai-integration[bot] Nov 24, 2024
2f12733
Fix documentation formatting issues:
devin-ai-integration[bot] Nov 24, 2024
a8c74e4
Fix Python 3.7 compatibility issues:
devin-ai-integration[bot] Nov 24, 2024
08b95b6
Fix Black formatting issues:
devin-ai-integration[bot] Nov 24, 2024
0c2fbc2
Fix Black formatting issues for Python 3.7 compatibility:
devin-ai-integration[bot] Nov 24, 2024
708d125
style: improve string formatting for Python 3.7 compatibility
devin-ai-integration[bot] Nov 24, 2024
5097c5b
fix: update code block formatting for Python 3.7 compatibility
devin-ai-integration[bot] Nov 24, 2024
a8811db
fix: improve Python 3.7 compatibility and code block formatting
devin-ai-integration[bot] Nov 24, 2024
16ff46d
fix: improve string formatting for Python 3.7 compatibility
devin-ai-integration[bot] Nov 24, 2024
ed21cbd
fix: update type hints and comment formatting for Python 3.7 compatib…
devin-ai-integration[bot] Nov 24, 2024
baea34e
fix: update string formatting and type hints for Python 3.7 compatibi…
devin-ai-integration[bot] Nov 24, 2024
7ce684b
Fix Python 3.7 compatibility in version-1.md
devin-ai-integration[bot] Nov 24, 2024
367d7bb
fix: Black formatting issues in documentation code examples
devin-ai-integration[bot] Nov 24, 2024
94f0f5f
fix: move image markdown outside of code block
devin-ai-integration[bot] Nov 24, 2024
9441b00
fix: Black formatting issues in documentation code examples
devin-ai-integration[bot] Nov 24, 2024
2d01d9b
fix: update comment formatting in version-1.md
devin-ai-integration[bot] Nov 24, 2024
eba5e13
Merge branch 'main' into devin/1732421325-poetry-to-uv
jxnl Dec 3, 2024
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
20 changes: 9 additions & 11 deletions docs/blog/posts/chain-of-density.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,16 +204,15 @@ class RewrittenSummary(BaseModel):
...,
description="This is a new, denser summary of identical length which covers every entity and detail from the previous summary plus the Missing Entities. It should have the same length ( ~ 80 words ) as the previous summary and should be easily understood without the Article",
)
absent: List[str] = Field(
absent: typing.List[str] = Field(
...,
default_factory=list,
description="this is a list of Entities found absent from the new summary that were present in the previous summary",
)
missing: List[str] = Field(
missing: typing.List[str] = Field(
default_factory=list,
description="This is a list of 1-3 informative Entities from the Article that are missing from the new summary which should be included in the next generated summary.",
)
```

!!! tip "Using Pydantic Validators with Instructor"

Expand Down Expand Up @@ -394,18 +393,18 @@ In order to prevent any contamination of data during testing, we randomly sample

```py hl_lines="2 9 11 13-21 40 43"
from typing import List
from chain_of_density import summarize_article #(1)!
from chain_of_density import summarize_article # (1)!
import csv
import logging
import instructor
from pydantic import BaseModel
from openai import OpenAI

client = instructor.from_openai(OpenAI()) # (2)!
client = instructor.from_openai(OpenAI()) # (2)!

logging.basicConfig(level=logging.INFO) #(3)!
logging.basicConfig(level=logging.INFO) # (3)!

instructions = instructor.Instructions( #(4)!
instructions = instructor.Instructions( # (4)!
name="Chain Of Density",
finetune_format="messages",
# log handler is used to save the data to a file
Expand All @@ -432,18 +431,17 @@ class GeneratedSummary(BaseModel):
description="This represents the final summary generated that captures the meaning of the original article which is as concise as possible. ",
)

@instructions.distil #(4)!
@instructions.distil # (4)!
def distil_summarization(text: str) -> GeneratedSummary:
summary_chain: List[str] = summarize_article(text)
return GeneratedSummary(summary=summary_chain[-1]) #(5)!
return GeneratedSummary(summary=summary_chain[-1]) # (5)!

with open("train.csv", "r") as file:
reader = csv.reader(file)
next(reader) # Skip the header
for article, summary in reader:
# Run Distillisation to generate the values
distil_summarization(article)
```

1. In this example, we're using the summarize_article that we defined up above. We saved it in a local file called `chain_of_density.py`,
hence the import
Expand Down Expand Up @@ -547,4 +545,4 @@ Interestingly, the model finetuned with the least examples seems to outperform t

Finetuning this iterative method was 20-40x faster while improving overall performance, resulting in massive efficiency gains by finetuning and distilling capabilities into specialized models.

We've seen how `Instructor` can make your life easier, from data modeling to distillation and finetuning. If you enjoy the content or want to try out `instructor` check out the [github](https://github.com/jxnl/instructor) and don't forget to give us a star!
We've seen how `Instructor` can make your life easier, from data modeling to distillation and finetuning. If you enjoy the content or want to try out `instructor` check out the [github](https://github.com/jxnl/instructor) and don't forget to give us a star!
39 changes: 8 additions & 31 deletions docs/blog/posts/introducing-structured-outputs.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,38 +117,15 @@ with client.beta.chat.completions.stream(
for event in stream:
if event.type == "content.delta":
print(event.snapshot, flush=True, end="\n")
#>
#> {"
#> {"name
#> {"name":"
#> {"name":"Jason
#> {"name":"Jason","
#> {"name":"Jason","age
#> {"name":"Jason","age":
#> {"name":"Jason","age":25
#> {"name":"Jason","age":25}
# >
#> {"
#> {"name
#> {"name":"
#> {"name":"Jason
#> {"name":"Jason","
#> {"name":"Jason","age
#> {"name":"Jason","age":
#> {"name":"Jason","age":25
#> {"name":"Jason","age":25}
```

### Unpredictable Latency Spikes

In order to benchmark the two modes, we made 200 identical requests to OpenAI and noted the time taken for each request to complete. The results are summarized in the following table:

| mode | mean | min | max | std_dev | variance |
| ------------------ | ----- | ----- | ------ | ------- | -------- |
| Tool Calling | 6.84 | 6.21 | 12.84 | 0.69 | 0.47 |
| Structured Outputs | 28.20 | 14.91 | 136.90 | 9.27 | 86.01 |

Structured Outputs suffers from unpredictable latency spikes while Tool Calling maintains consistent performance. This could cause users to occasionally experience significant delays in response times, potentially impacting the overall user satisfication and retention rates.
# > {"name
# > {"name":"
# > {"name":"Jason
# > {"name":"Jason","
# > {"name":"Jason","age
# > {"name":"Jason","age":
# > {"name":"Jason","age":25
# > {"name":"Jason","age":25}

## Why use `instructor`

Expand Down
115 changes: 67 additions & 48 deletions docs/blog/posts/multimodal-gemini.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,74 +87,93 @@ print(resp)

```python
Recomendations(
chain_of_thought='The video recommends visiting Takayama city, in the Hida Region, Gifu Prefecture. The
video suggests visiting the Miyagawa Morning Market, to try the Sarubobo good luck charms, and to enjoy the
cookie cup espresso, made by Koma Coffee. Then, the video suggests visiting a traditional Japanese Cafe,
called Kissako Katsure, and try their matcha and sweets. Afterwards, the video suggests to visit the Sanmachi
Historic District, where you can find local crafts and delicious foods. The video recommends trying Hida Wagyu
beef, at the Kin no Kotte Ushi shop, or to have a sit-down meal at the Kitchen Hida. Finally, the video
recommends visiting Shirakawa-go, a World Heritage Site in Gifu Prefecture.',
description='This video recommends a number of places to visit in Takayama city, in the Hida Region, Gifu
Prefecture. It shows some of the local street food and highlights some of the unique shops and restaurants in
the area.',
chain_of_thought=" ".join([
"The video recommends visiting Takayama city, in the Hida Region, Gifu Prefecture.",
"The video suggests visiting the Miyagawa Morning Market, to try the Sarubobo good luck charms,",
"and to enjoy the cookie cup espresso, made by Koma Coffee. Then, the video suggests visiting",
"a traditional Japanese Cafe, called Kissako Katsure, and try their matcha and sweets.",
"Afterwards, the video suggests to visit the Sanmachi Historic District, where you can find",
"local crafts and delicious foods. The video recommends trying Hida Wagyu beef, at the Kin",
"no Kotte Ushi shop, or to have a sit-down meal at the Kitchen Hida. Finally, the video",
"recommends visiting Shirakawa-go, a World Heritage Site in Gifu Prefecture."
]),
description=" ".join([
"This video recommends a number of places to visit in Takayama city, in the Hida Region, Gifu",
"Prefecture. It shows some of the local street food and highlights some of the unique shops and restaurants in",
"the area."
]),
destinations=[
TouristDestination(
name='Takayama',
description='Takayama is a city at the base of the Japan Alps, located in the Hida Region of
Gifu.',
location='Hida Region, Gifu Prefecture'
name="Takayama",
description=(
"Takayama is a city at the base of the Japan Alps, located in the Hida Region of "
"Gifu."
),
location="Hida Region, Gifu Prefecture"
),
TouristDestination(
name='Miyagawa Morning Market',
description="The Miyagawa Morning Market, or the Miyagawa Asai-chi in Japanese, is a market that
has existed officially since the Edo Period, more than 100 years ago. It's open every single day, rain or
shine, from 7am to noon.",
location='Hida Takayama'
name="Miyagawa Morning Market",
description=(
"The Miyagawa Morning Market, or the Miyagawa Asai-chi in Japanese, is a market that "
"has existed officially since the Edo Period, more than 100 years ago. It's open every "
"single day, rain or shine, from 7am to noon."
),
location="Hida Takayama"
),
TouristDestination(
name='Nakaya - Handmade Hida Sarubobo',
description='The Nakaya shop sells handcrafted Sarubobo good luck charms.',
location='Hida Takayama'
name="Nakaya - Handmade Hida Sarubobo",
description="The Nakaya shop sells handcrafted Sarubobo good luck charms.",
location="Hida Takayama"
),
TouristDestination(
name='Koma Coffee',
description="Koma Coffee is a shop that has been in business for about 50 or 60 years, and they
serve coffee in a cookie cup. They've been serving coffee for about 10 years.",
location='Hida Takayama'
name="Koma Coffee",
description=(
"Koma Coffee is a shop that has been in business for about 50 or 60 years, and they "
"serve coffee in a cookie cup. They've been serving coffee for about 10 years."
),
location="Hida Takayama"
),
TouristDestination(
name='Kissako Katsure',
description='Kissako Katsure is a traditional Japanese style cafe, called Kissako, and the name
means would you like to have some tea. They have a variety of teas and sweets.',
location='Hida Takayama'
name="Kissako Katsure",
description=(
"Kissako Katsure is a traditional Japanese style cafe, called Kissako, and the name "
"means would you like to have some tea. They have a variety of teas and sweets."
),
location="Hida Takayama"
),
TouristDestination(
name='Sanmachi Historic District',
description='Sanmachi Dori is a Historic Merchant District in Takayama, all of the buildings here
have been preserved to look as they did in the Edo Period.',
location='Hida Takayama'
name="Sanmachi Historic District",
description=(
"Sanmachi Dori is a Historic Merchant District in Takayama, all of the buildings here "
"have been preserved to look as they did in the Edo Period."
),
location="Hida Takayama"
),
TouristDestination(
name='Suwa Orchard',
description='The Suwa Orchard has been in business for more than 50 years.',
location='Hida Takayama'
name="Suwa Orchard",
description="The Suwa Orchard has been in business for more than 50 years.",
location="Hida Takayama"
),
TouristDestination(
name='Kitchen HIDA',
description='Kitchen HIDA is a restaurant with a 50 year history, known for their Hida Beef dishes
and for using a lot of local ingredients.',
location='Hida Takayama'
name="Kitchen HIDA",
description=(
"Kitchen HIDA is a restaurant with a 50 year history, known for their Hida Beef dishes "
"and for using a lot of local ingredients."
),
location="Hida Takayama"
),
TouristDestination(
name='Kin no Kotte Ushi',
description='Kin no Kotte Ushi is a shop known for selling Beef Sushi, especially Hida Wagyu Beef
Sushi. Their sushi is medium rare.',
location='Hida Takayama'
name="Kin no Kotte Ushi",
description=(
"Kin no Kotte Ushi is a shop known for selling Beef Sushi, especially Hida Wagyu Beef "
"Sushi. Their sushi is medium rare."
),
location="Hida Takayama"
),
TouristDestination(
name='Shirakawa-go',
description='Shirakawa-go is a World Heritage Site in Gifu Prefecture.',
location='Gifu Prefecture'
name="Shirakawa-go",
description="Shirakawa-go is a World Heritage Site in Gifu Prefecture.",
location="Gifu Prefecture"
)
]
)
Expand Down
46 changes: 24 additions & 22 deletions docs/blog/posts/version-1.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,12 @@ Now, whenever you call `client.chat.completions.create` the `model` and `tempera
When I first started working on this project, my goal was to ensure that we weren't introducing any new standards. Instead, our focus was on maintaining compatibility with existing ones. By creating our own client, we can seamlessly proxy OpenAI's `chat.completions.create` and Anthropic's `messages.create` methods. This approach allows us to provide a smooth upgrade path for your client, enabling support for all the latest models and features as they become available. Additionally, this strategy safeguards us against potential downstream changes.

```python
from __future__ import annotations # Required for Python 3.7
import openai
import anthropic
import litellm
import instructor
from typing import TypeVar
from typing import TypeVar, Type, Any

T = TypeVar("T")

Expand All @@ -77,10 +78,11 @@ client = instructor.from_litellm(litellm.completion)

# all of these will route to the same underlying create function
# allow you to add instructor to try it out, while easily removing it
client.create(model="gpt-4", response_model=type[T]) -> T
client.chat.completions.create(model="gpt-4", response_model=type[T]) -> T
client.messages.create(model="gpt-4", response_model=type[T]) -> T
```


def create(model: str, response_model: 'Any') -> 'T': ... # type: ignore
def chat_completions_create(model: str, response_model: 'Any') -> 'T': ... # type: ignore
def messages_create(model: str, response_model: 'Any') -> 'T': ... # type: ignore

## Type are infered correctly

Expand Down Expand Up @@ -204,25 +206,25 @@ user_stream = client.chat.completions.create_partial(

for user in user_stream:
print(user)
#> name=None age=None
#> name=None age=None
#> name=None age=None
#> name=None age=25
#> name=None age=25
#> name=None age=25
#> name='' age=25
#> name='John' age=25
#> name='John Smith' age=25
#> name='John Smith' age=25
# name=None age=None
# name='' age=None
# name='John' age=None
# name='John Doe' age=None
# name='John Doe' age=30
# > name=None age=None
# > name=None age=None
# > name=None age=None
# > name=None age=25
# > name=None age=25
# > name=None age=25
# > name='' age=25
# > name='John' age=25
# > name='John Smith' age=25
# > name='John Smith' age=25
# > name=None age=None
# > name='' age=None
# > name='John' age=None
# > name='John Doe' age=None
# > name='John Doe' age=30

# Note: The return type is Generator[User, None, None]
```

Notice now that the type infered is `Generator[User, None]`

![generator](./img/generator.png)

### Streaming Iterables: `create_iterable`
Expand Down
Loading
Loading