-
-
Notifications
You must be signed in to change notification settings - Fork 722
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
34 changed files
with
2,836 additions
and
162 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
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,113 @@ | ||
# Data extraction from slides | ||
|
||
In this guide, we demonstrate how to extract data from slides. | ||
|
||
!!! tips "Motivation" | ||
|
||
When we want to translate key information from slides into structured data, simply isolating the text and running extraction might not be enough. Sometimes the important data is in the images on the slides, so we should consider including them in our extraction pipeline. | ||
|
||
## Defining the necessary Data Structures | ||
|
||
Let's say we want to extract the competitors from various presentations and categorize them according to their respective industries. | ||
|
||
Our data model will have `Industry` which will be a list of `Competitor`'s for a specific industry, and `Competition` which will aggregate the competitors for all the industries. | ||
|
||
```python | ||
from openai import OpenAI | ||
from pydantic import BaseModel, Field | ||
from typing import Optional, List | ||
|
||
class Competitor(BaseModel): | ||
name: str | ||
features: Optional[List[str]] | ||
|
||
|
||
# Define models | ||
class Industry(BaseModel): | ||
""" | ||
Represents competitors from a specific industry extracted from an image using AI. | ||
""" | ||
|
||
name: str = Field( | ||
description="The name of the industry" | ||
) | ||
competitor_list: List[Competitor] = Field( | ||
description="A list of competitors for this industry" | ||
) | ||
|
||
class Competition(BaseModel): | ||
""" | ||
This class serves as a structured representation of | ||
competitors and their qualities. | ||
""" | ||
|
||
industry_list: List[IndustryCompetition] = Field( | ||
description="A list of industries and their competitors" | ||
) | ||
``` | ||
|
||
## Competitors extraction | ||
|
||
To extract competitors from slides we will define a function which will read images from urls and extract the relevant information from them. | ||
|
||
```python | ||
import instructor | ||
from openai import OpenAI | ||
|
||
# Apply the patch to the OpenAI client | ||
# enables response_model keyword | ||
client = instructor.patch( | ||
OpenAI(), mode=instructor.Mode.MD_JSON | ||
) | ||
|
||
# Define functions | ||
def read_images(image_urls: List[str]) -> Competition: | ||
""" | ||
Given a list of image URLs, identify the competitors in the images. | ||
""" | ||
return client.chat.completions.create( | ||
model="gpt-4-vision-preview", | ||
response_model=Competition, | ||
max_tokens=2048, | ||
temperature=0, | ||
messages=[ | ||
{ | ||
"role": "user", | ||
"content": [ | ||
{ | ||
"type": "text", | ||
"text": "Identify competitors and generate key features for each competitor.", | ||
}, | ||
*[ | ||
{"type": "image_url", "image_url": {"url": url}} | ||
for url in image_urls | ||
], | ||
], | ||
} | ||
], | ||
) | ||
``` | ||
|
||
## Execution | ||
|
||
Finally, we will run the previous function with a few sample slides to see the data extractor in action. | ||
|
||
As we can see, our model extracted the relevant information for each competitor regardless of how this information was formatted in the original presentations. | ||
|
||
```python | ||
url = [ | ||
'https://miro.medium.com/v2/resize:fit:1276/0*h1Rsv-fZWzQUyOkt', | ||
'https://earlygame.vc/wp-content/uploads/2020/06/startup-pitch-deck-5.jpg' | ||
] | ||
model = read_images(url) | ||
print(model.model_json_dump(indent=2)) | ||
``` | ||
industry_list=[ | ||
|
||
Industry(name='Accommodation and Hospitality', competitor_list=[Competitor(name='CouchSurfing', features=['Affordable', 'Online Transaction']), Competitor(name='Craigslist', features=['Affordable', 'Offline Transaction']), Competitor(name='BedandBreakfast.com', features=['Affordable', 'Offline Transaction']), Competitor(name='AirBed&Breakfast', features=['Affordable', 'Online Transaction']), Competitor(name='Hostels.com', features=['Affordable', 'Online Transaction']), Competitor(name='VRBO', features=['Expensive', 'Offline Transaction']), Competitor(name='Rentahome', features=['Expensive', 'Online Transaction']), Competitor(name='Orbitz', features=['Expensive', 'Online Transaction']), Competitor(name='Hotels.com', features=['Expensive', 'Online Transaction'])]), | ||
|
||
Industry(name='Wine E-commerce', competitor_list=[Competitor(name='WineSimple', features=['Ecommerce Retailers', 'True Personalized Selections', 'Brand Name Wine', 'No Inventory Cost', 'Target Mass Market']), Competitor(name='NakedWines', features=['Ecommerce Retailers', 'Target Mass Market']), Competitor(name='Club W', features=['Ecommerce Retailers', 'Brand Name Wine', 'Target Mass Market']), Competitor(name='Tasting Room', features=['Ecommerce Retailers', 'True Personalized Selections', 'Brand Name Wine']), Competitor(name='Drync', features=['Ecommerce Retailers', 'True Personalized Selections', 'No Inventory Cost']), Competitor(name='Hello Vino', features=['Ecommerce Retailers', 'Brand Name Wine', 'Target Mass Market'])]) | ||
|
||
] | ||
``` | ||
``` |
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,92 @@ | ||
# Instructor Hub | ||
|
||
Welcome to instructor hub, the goal of this project is to provide a set of tutorials and examples to help you get started, and allow you to pull in the code you need to get started with `instructor` | ||
|
||
Make sure you're using the latest version of `instructor` by running: | ||
|
||
```bash | ||
pip install -U instructor | ||
``` | ||
|
||
## Contributing | ||
|
||
We welcome contributions to the instructor hub, if you have a tutorial or example you'd like to add, please open a pull request in `docs/hub` and we'll review it. | ||
|
||
1. The code must be in a single file | ||
2. Make sure that its referenced in the `mkdocs.yml` | ||
3. Make sure that the code is unit tested. | ||
|
||
### Using pytest_examples | ||
|
||
By running the following command you can run the tests and update the examples. This ensures that the examples are always up to date. | ||
Linted correctly and that the examples are working, make sure to include a `if __name__ == "__main__":` block in your code and add some asserts to ensure that the code is working. | ||
|
||
```bash | ||
poetry run pytest tests/openai/docs/test_hub.py --update-examples | ||
``` | ||
|
||
## CLI Usage | ||
|
||
Instructor hub comes with a command line interface (CLI) that allows you to view and interact with the tutorials and examples and allows you to pull in the code you need to get started with the API. | ||
|
||
### List Cookbooks | ||
|
||
By running `instructor hub list` you can see all the available tutorials and examples. By clickony (doc) you can see the full tutorial back on this website. | ||
|
||
```bash | ||
$ instructor hub list --sort | ||
``` | ||
|
||
| hub_id | slug | title | n_downloads | | ||
| ------ | ----------------------------- | ----------------------------- | ----------- | | ||
| 2 | multiple_classification (doc) | Multiple Classification Model | 24 | | ||
| 1 | single_classification (doc) | Single Classification Model | 2 | | ||
|
||
### Searching for Cookbooks | ||
|
||
You can search for a tutorial by running `instructor hub list -q <QUERY>`. This will return a list of tutorials that match the query. | ||
|
||
```bash | ||
$ instructor hub list -q multi | ||
``` | ||
|
||
| hub_id | slug | title | n_downloads | | ||
| ------ | ----------------------------- | ----------------------------- | ----------- | | ||
| 2 | multiple_classification (doc) | Multiple Classification Model | 24 | | ||
|
||
### Reading a Cookbook | ||
|
||
To read a tutorial, you can run `instructor hub pull --id <hub_id> --page` to see the full tutorial in the terminal. You can use `j,k` to scroll up and down, and `q` to quit. You can also run it without `--page` to print the tutorial to the terminal. | ||
|
||
```bash | ||
$ instructor hub pull --id 2 --page | ||
``` | ||
|
||
### Pulling in Code | ||
|
||
You can pull in the code with `--py --output=<filename>` to save the code to a file, or you cal also run it without `--output` to print the code to the terminal. | ||
|
||
```bash | ||
$ instructor hub pull --id 2 --py --output=run.py | ||
$ instructor hub pull --id 2 --py > run.py | ||
``` | ||
|
||
You can run the code instantly if you `|` it to `python`: | ||
|
||
```bash | ||
$ instructor hub pull --id 2 --py | python | ||
``` | ||
|
||
## Call for Contributions | ||
|
||
We're looking for a bunch more hub examples, if you have a tutorial or example you'd like to add, please open a pull request in `docs/hub` and we'll review it. | ||
|
||
- [ ] Converting the cookbooks to the new format | ||
- [ ] Validator examples | ||
- [ ] Data extraction examples | ||
- [ ] Streaming examples (Iterable and Partial) | ||
- [ ] Batch Parsing examples | ||
- [ ] Open Examples, together, anyscale, ollama, llama-cpp, etc | ||
- [ ] Query Expansion examples | ||
- [ ] Batch Data Processing examples | ||
- [ ] Batch Data Processing examples with Cache |
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,51 @@ | ||
For multi-label classification, we introduce a new enum class and a different Pydantic model to handle multiple labels. | ||
|
||
```python | ||
import openai | ||
import instructor | ||
|
||
from typing import List, Literal | ||
from pydantic import BaseModel, Field | ||
|
||
# Apply the patch to the OpenAI client | ||
# enables response_model keyword | ||
client = instructor.patch(openai.OpenAI()) | ||
|
||
LABELS = Literal["ACCOUNT", "BILLING", "GENERAL_QUERY"] | ||
|
||
|
||
class MultiClassPrediction(BaseModel): | ||
labels: List[LABELS] = Field( | ||
..., | ||
description="Only select the labels that apply to the support ticket.", | ||
) | ||
|
||
|
||
def multi_classify(data: str) -> MultiClassPrediction: | ||
return client.chat.completions.create( | ||
model="gpt-4-turbo-preview", # gpt-3.5-turbo fails | ||
response_model=MultiClassPrediction, | ||
messages=[ | ||
{ | ||
"role": "system", | ||
"content": f"You are a support agent at a tech company. Only select the labels that apply to the support ticket.", | ||
}, | ||
{ | ||
"role": "user", | ||
"content": f"Classify the following support ticket: {data}", | ||
}, | ||
], | ||
) # type: ignore | ||
|
||
|
||
if __name__ == "__main__": | ||
ticket = "My account is locked and I can't access my billing info." | ||
prediction = multi_classify(ticket) | ||
assert {"ACCOUNT", "BILLING"} == {label for label in prediction.labels} | ||
print("input:", ticket) | ||
#> input: My account is locked and I can't access my billing info. | ||
print("labels:", LABELS) | ||
#> labels: typing.Literal['ACCOUNT', 'BILLING', 'GENERAL_QUERY'] | ||
print("prediction:", prediction) | ||
#> prediction: labels=['ACCOUNT', 'BILLING'] | ||
``` |
Oops, something went wrong.