# Pydantic is all you need, for openai function calls.
Check out the [docs](https://openai-function-call.onrender.com/)!
We try to provides a powerful and efficient approach to output parsing when interacting with OpenAI's Function Call API. One that is framework agnostic and minimizes any dependencies. It leverages the data validation capabilities of the Pydantic library to handle output parsing in a more structured and reliable manner.
If you have any feedback, leave an issue or hit me up on [twitter](https://twitter.com/jxnlco).
This repo also contains a range of examples I've used in experimentation and in production and I welcome new contributions for different types of schemas.
## Support
Follow me on twitter and consider helping pay for openai tokens!
[![Twitter URL](https://img.shields.io/twitter/url/https/twitter.com/jxnlco.svg?style=social&label=Follow%20%40jxnlco)](https://twitter.com/jxnlco) [!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/jxnl)
## Installation
Ensure you have Python version 3.9 or above.
```python
pip install openai-function-call
```
## Contributing
To get started, clone the repository
```bash
git clone https://github.com/jxnl/openai_function_call.git
```
Next, install the necessary Python packages from the requirements.txt file:
```bash
pip install -r requirements.txt
```
### Poetry
We also use poetry if you'd like
```bash
poetry build
```
Your contributions are welcome! If you have great examples or find neat patterns, clone the repo and add another example.
Check out the issues for any ideas if you want to learn. The goal is to find great patterns and cool examples to highlight.
If you encounter any issues or want to provide feedback, you can create an issue in this repository. You can also reach out to me on Twitter at @jxnlco.
## Usage
This module simplifies the interaction with the OpenAI API, enabling a more structured and predictable conversation with the AI. Below are examples showcasing the use of function calls and schemas with OpenAI and Pydantic.
### Example 1: Function Calls
```python
import openai
from openai_function_call import openai_function
@openai_function
def sum(a:int, b:int) -> int:
"""Sum description adds a + b"""
return a + b
completion = openai.ChatCompletion.create(
model="gpt-3.5-turbo-0613",
temperature=0,
functions=[sum.openai_schema],
messages=[
{
"role": "system",
"content": "You must use the `sum` function instead of adding yourself.",
},
{
"role": "user",
"content": "What is 6+3 use the `sum` function",
},
],
)
result = sum.from_response(completion)
print(result) # 9
```
### Example 2: Schema Extraction
```python
import openai
from openai_function_call import OpenAISchema
from pydantic import Field
class UserDetails(OpenAISchema):
"""User Details"""
name: str = Field(..., description="User's name")
age: int = Field(..., description="User's age")
completion = openai.ChatCompletion.create(
model="gpt-3.5-turbo-0613",
functions=[UserDetails.openai_schema],
messages=[
{"role": "system", "content": "I'm going to ask for user details. Use UserDetails to parse this data."},
{"role": "user", "content": "My name is John Doe and I'm 30 years old."},
],
)
user_details = UserDetails.from_response(completion)
print(user_details) # UserDetails(name="John Doe", age=30)
```
### Example 2.1: Using the Decorator
The following will also work but we're having issues with propogating type hints
so language services throw errors for methods like `.openai_schema`. We'd welcome a PR to fix this!
```python
from openai_function_call import openai_schema
@openai_schema
class UserDetails(BaseModel):
"""User Details"""
name: str = Field(..., description="User's name")
age: int = Field(..., description="User's age")
```
### Example 3: Using the DSL
```python
from pprint import pprint
from openai_function_call import OpenAISchema
from openai_function_call.dsl import ChatCompletion, MultiTask, messages as m
from openai_function_call.dsl.messages import SystemIdentity, SystemTask, SystemStyle, SystemGuidelines, SystemTips
# Define a subtask you'd like to extract from then,
# We'll use MultTask to easily map it to a List[Search]
# so we can extract more than one
class Search(OpenAISchema):
id: int
query: str
tasks = (
ChatCompletion(name="Acme Inc Email Segmentation", model="gpt-3.5-turbo-0613")
| SystemIdentity(identity="World class state of the art agent") # if no identity is provided, this is the default one
| SystemTask(task="Segment emails into search queries")
| SystemStyle(style="Professional, clear and concise")
| SystemGuidelines(guidelines=[
'You never swear',
'You are polite',
'You say please and thank you often.'
])
| SystemTips(tips=[
"When unsure about the correct segmentation, try to think about the task as a whole",
"If acronyms are used expand them to their full form",
"Use multiple phrases to describe the same thing"]
)
| MultiTask(subtask_class=Search)
| m.TaggedMessage(
tag="email",
content="Can you find the video I sent last week and also the post about dogs",
)
| m.ChainOfThought()
)
# Its important that this just builds you request,
# all these | operators are overloaded and all we do is compile
# it to the openai kwargs
# Also note that the System components are combined sequentially
# so the order matters!
assert isinstance(tasks, ChatCompletion)
pprint(tasks.kwargs, indent=3)
"""
{
"messages": [
{
"role": "system",
"content": "You are a world class state of the art agent.\n\nYour purpose is to correctly complete this task:
`Segment emails into search queries`.\n\nYour style when answering is professional, clear and concise\n\n
These are the guidelines you consider when completing your task:\n\n* You never swear\n* You are polite\n* You say please and thank you often.\n\nHere are some tips to help you complete the task:\n\n* When unsure about the correct segmentation, try to think about the task as a whole\n* If acronyms are used expand them to their full form\n* Use multiple phrases to describe the same thing"
},
...
{
"role": "user",
"content": "<email>Can you find the video I sent last week and also the post about dogs</email>"
},
{
"role": "assistant",
"content": "Lets think step by step to get the correct answer:"
}
],
"functions": [
{
"name": "MultiSearch",
"description": "Correct segmentation of `Search` tasks",
"parameters": {
"type": "object",
"properties": {
"tasks": {
"description": "Correctly segmented list of `Search` tasks",
"type": "array",
"items": {"$ref": "#/definitions/Search"}
}
},
"definitions": {
"Search": {
"type": "object",
"properties": {
"id": {"type": "integer"},
"query": {"type": "string"}
},
"required": ["id", "query"]
}
},
"required": ["tasks"]
}
}
],
"function_call": {"name": "MultiSearch"},
"max_tokens": 1000,
"temperature": 0.1,
"model": "gpt-3.5-turbo-0613"
"""
# Once we call .create we'll be returned with a multitask object that contains our list of task
result = tasks.create()
for task in result.tasks:
# We can now extract the list of tasks as we could normally
assert isinstance(task, Search)
```
## Advanced Usage
If you want to see more examples checkout the examples folder!
## License
This project is licensed under the terms of the MIT license.
For more details, refer to the LICENSE file in the repository.
Raw data
{
"_id": null,
"home_page": "https://github.com/jxnl/openai_function_call",
"name": "openai-function-call",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.9,<4.0",
"maintainer_email": "",
"keywords": "",
"author": "Jason",
"author_email": "jason@jxnl.co",
"download_url": "https://files.pythonhosted.org/packages/5a/83/3a076a0a5724c54bbb09dde8c9e40b0bc5b98dc0e04ac4e2eef27b064bbf/openai_function_call-0.2.3.tar.gz",
"platform": null,
"description": "# Pydantic is all you need, for openai function calls.\n\nCheck out the [docs](https://openai-function-call.onrender.com/)!\n\nWe try to provides a powerful and efficient approach to output parsing when interacting with OpenAI's Function Call API. One that is framework agnostic and minimizes any dependencies. It leverages the data validation capabilities of the Pydantic library to handle output parsing in a more structured and reliable manner.\nIf you have any feedback, leave an issue or hit me up on [twitter](https://twitter.com/jxnlco).\n\nThis repo also contains a range of examples I've used in experimentation and in production and I welcome new contributions for different types of schemas.\n\n## Support\n\nFollow me on twitter and consider helping pay for openai tokens!\n\n[![Twitter URL](https://img.shields.io/twitter/url/https/twitter.com/jxnlco.svg?style=social&label=Follow%20%40jxnlco)](https://twitter.com/jxnlco) [![\"Buy Me A Coffee\"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/jxnl)\n\n## Installation\n\nEnsure you have Python version 3.9 or above.\n\n```python\npip install openai-function-call\n```\n\n## Contributing\n\nTo get started, clone the repository\n\n```bash\ngit clone https://github.com/jxnl/openai_function_call.git\n```\n\nNext, install the necessary Python packages from the requirements.txt file:\n\n```bash\npip install -r requirements.txt\n```\n\n### Poetry\n\nWe also use poetry if you'd like\n\n```bash\npoetry build\n```\n\nYour contributions are welcome! If you have great examples or find neat patterns, clone the repo and add another example.\nCheck out the issues for any ideas if you want to learn. The goal is to find great patterns and cool examples to highlight.\n\nIf you encounter any issues or want to provide feedback, you can create an issue in this repository. You can also reach out to me on Twitter at @jxnlco.\n\n## Usage\n\nThis module simplifies the interaction with the OpenAI API, enabling a more structured and predictable conversation with the AI. Below are examples showcasing the use of function calls and schemas with OpenAI and Pydantic.\n\n### Example 1: Function Calls\n\n```python\nimport openai\nfrom openai_function_call import openai_function\n\n@openai_function\ndef sum(a:int, b:int) -> int:\n \"\"\"Sum description adds a + b\"\"\"\n return a + b\n\ncompletion = openai.ChatCompletion.create(\n model=\"gpt-3.5-turbo-0613\",\n temperature=0,\n functions=[sum.openai_schema],\n messages=[\n {\n \"role\": \"system\",\n \"content\": \"You must use the `sum` function instead of adding yourself.\",\n },\n {\n \"role\": \"user\",\n \"content\": \"What is 6+3 use the `sum` function\",\n },\n ],\n )\n\nresult = sum.from_response(completion)\nprint(result) # 9\n```\n\n### Example 2: Schema Extraction\n\n```python\nimport openai\nfrom openai_function_call import OpenAISchema\n\nfrom pydantic import Field\n\nclass UserDetails(OpenAISchema):\n \"\"\"User Details\"\"\"\n name: str = Field(..., description=\"User's name\")\n age: int = Field(..., description=\"User's age\")\n\ncompletion = openai.ChatCompletion.create(\n model=\"gpt-3.5-turbo-0613\",\n functions=[UserDetails.openai_schema],\n messages=[\n {\"role\": \"system\", \"content\": \"I'm going to ask for user details. Use UserDetails to parse this data.\"},\n {\"role\": \"user\", \"content\": \"My name is John Doe and I'm 30 years old.\"},\n ],\n)\n\nuser_details = UserDetails.from_response(completion)\nprint(user_details) # UserDetails(name=\"John Doe\", age=30)\n```\n\n### Example 2.1: Using the Decorator\n\nThe following will also work but we're having issues with propogating type hints\nso language services throw errors for methods like `.openai_schema`. We'd welcome a PR to fix this! \n\n```python\nfrom openai_function_call import openai_schema\n\n@openai_schema\nclass UserDetails(BaseModel):\n \"\"\"User Details\"\"\"\n name: str = Field(..., description=\"User's name\")\n age: int = Field(..., description=\"User's age\")\n```\n\n### Example 3: Using the DSL\n\n```python\nfrom pprint import pprint\n\nfrom openai_function_call import OpenAISchema\nfrom openai_function_call.dsl import ChatCompletion, MultiTask, messages as m\nfrom openai_function_call.dsl.messages import SystemIdentity, SystemTask, SystemStyle, SystemGuidelines, SystemTips\n\n# Define a subtask you'd like to extract from then,\n# We'll use MultTask to easily map it to a List[Search]\n# so we can extract more than one\nclass Search(OpenAISchema):\n id: int\n query: str\n\ntasks = (\n ChatCompletion(name=\"Acme Inc Email Segmentation\", model=\"gpt-3.5-turbo-0613\")\n | SystemIdentity(identity=\"World class state of the art agent\") # if no identity is provided, this is the default one\n | SystemTask(task=\"Segment emails into search queries\")\n | SystemStyle(style=\"Professional, clear and concise\")\n | SystemGuidelines(guidelines=[\n 'You never swear',\n 'You are polite',\n 'You say please and thank you often.'\n ])\n | SystemTips(tips=[\n \"When unsure about the correct segmentation, try to think about the task as a whole\",\n \"If acronyms are used expand them to their full form\",\n \"Use multiple phrases to describe the same thing\"]\n )\n | MultiTask(subtask_class=Search)\n | m.TaggedMessage(\n tag=\"email\",\n content=\"Can you find the video I sent last week and also the post about dogs\",\n )\n | m.ChainOfThought()\n)\n# Its important that this just builds you request,\n# all these | operators are overloaded and all we do is compile\n# it to the openai kwargs\n# Also note that the System components are combined sequentially\n# so the order matters!\nassert isinstance(tasks, ChatCompletion)\npprint(tasks.kwargs, indent=3)\n\"\"\"\n{\n \"messages\": [\n {\n \"role\": \"system\",\n \"content\": \"You are a world class state of the art agent.\\n\\nYour purpose is to correctly complete this task:\n `Segment emails into search queries`.\\n\\nYour style when answering is professional, clear and concise\\n\\n\n These are the guidelines you consider when completing your task:\\n\\n* You never swear\\n* You are polite\\n* You say please and thank you often.\\n\\nHere are some tips to help you complete the task:\\n\\n* When unsure about the correct segmentation, try to think about the task as a whole\\n* If acronyms are used expand them to their full form\\n* Use multiple phrases to describe the same thing\"\n },\n ...\n {\n \"role\": \"user\",\n \"content\": \"<email>Can you find the video I sent last week and also the post about dogs</email>\"\n },\n {\n \"role\": \"assistant\",\n \"content\": \"Lets think step by step to get the correct answer:\"\n }\n ],\n \"functions\": [\n {\n \"name\": \"MultiSearch\",\n \"description\": \"Correct segmentation of `Search` tasks\",\n \"parameters\": {\n \"type\": \"object\",\n \"properties\": {\n \"tasks\": {\n \"description\": \"Correctly segmented list of `Search` tasks\",\n \"type\": \"array\",\n \"items\": {\"$ref\": \"#/definitions/Search\"}\n }\n },\n \"definitions\": {\n \"Search\": {\n \"type\": \"object\",\n \"properties\": {\n \"id\": {\"type\": \"integer\"},\n \"query\": {\"type\": \"string\"}\n },\n \"required\": [\"id\", \"query\"]\n }\n },\n \"required\": [\"tasks\"]\n }\n }\n ],\n \"function_call\": {\"name\": \"MultiSearch\"},\n \"max_tokens\": 1000,\n \"temperature\": 0.1,\n \"model\": \"gpt-3.5-turbo-0613\"\n\"\"\"\n\n# Once we call .create we'll be returned with a multitask object that contains our list of task\nresult = tasks.create()\n\nfor task in result.tasks:\n # We can now extract the list of tasks as we could normally\n assert isinstance(task, Search)\n```\n\n## Advanced Usage\n\nIf you want to see more examples checkout the examples folder!\n\n## License\n\nThis project is licensed under the terms of the MIT license.\n\nFor more details, refer to the LICENSE file in the repository.\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Helper functions that allow us to improve openai's function_call ergonomics",
"version": "0.2.3",
"project_urls": {
"Homepage": "https://github.com/jxnl/openai_function_call",
"Repository": "https://github.com/jxnl/openai_function_call"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "f2f382bf36f1c33d96cf8e37e617b250609982ac62531c3b782149d3e2ec0786",
"md5": "42df7840f5796948bf0748e26e23df1c",
"sha256": "5cb6eb6ceded286ea66e6da98653e1c3fc3f8d9988448e74c711947438f7f739"
},
"downloads": -1,
"filename": "openai_function_call-0.2.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "42df7840f5796948bf0748e26e23df1c",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9,<4.0",
"size": 15366,
"upload_time": "2023-08-16T18:35:51",
"upload_time_iso_8601": "2023-08-16T18:35:51.857898Z",
"url": "https://files.pythonhosted.org/packages/f2/f3/82bf36f1c33d96cf8e37e617b250609982ac62531c3b782149d3e2ec0786/openai_function_call-0.2.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "5a833a076a0a5724c54bbb09dde8c9e40b0bc5b98dc0e04ac4e2eef27b064bbf",
"md5": "59e69d24327eb9def5023830b9c33393",
"sha256": "c56ccb3d47e2a8c84feaeb26b38371ac663e83db4f68376cd0f975bd9ca4d130"
},
"downloads": -1,
"filename": "openai_function_call-0.2.3.tar.gz",
"has_sig": false,
"md5_digest": "59e69d24327eb9def5023830b9c33393",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9,<4.0",
"size": 14167,
"upload_time": "2023-08-16T18:35:53",
"upload_time_iso_8601": "2023-08-16T18:35:53.507309Z",
"url": "https://files.pythonhosted.org/packages/5a/83/3a076a0a5724c54bbb09dde8c9e40b0bc5b98dc0e04ac4e2eef27b064bbf/openai_function_call-0.2.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-08-16 18:35:53",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "jxnl",
"github_project": "openai_function_call",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [],
"lcname": "openai-function-call"
}