OpenaiEx Beta API User Guide
Mix.install([
{:openai_ex, "~> 0.9.16"},
{:kino, "~> 0.17.0"}
])
Introduction
This guide covers the beta APIs in OpenaiEx. These APIs are subject to change and may not be stable. The beta APIs include Assistants, Threads and Runs, and related functionality.
apikey = System.fetch_env!("LB_OPENAI_API_KEY")
openai = OpenaiEx.new(apikey)
Assistant
alias OpenaiEx.Beta.Assistants
Create Assistant
To create an assistant with model and instructions, call the Assistant.create()
function.
First, we setup the create request parameters. This request sets up an Assistant with a code interpreter tool.
hr_assistant_req =
Assistants.new(
instructions:
"You are an HR bot, and you have access to files to answer employee questions about company policies.",
name: "HR Helper",
tools: [%{type: "file_search"}],
model: "gpt-4o-mini"
)
Then we call the create function
{:ok, asst} = openai |> Assistants.create(hr_assistant_req)
Retrieve Assistant
Extract the id field for the assistant
assistant_id = asst["id"]
which can then be used to retrieve the Assistant fields, using the Assistant.retrieve()
function.
openai |> Assistants.retrieve(assistant_id)
Modify Assistant
Once created, an assistant can be modified using the Assistant.update()
function.
Now we will show an example assistant request using the retrieval tool with a set of files. First we set up the files (in this case a sample HR document) by uploading using the File
API.
fetch_blob = fn url ->
Finch.build(:get, url) |> Finch.request!(OpenaiEx.Finch) |> Map.get(:body)
end
alias OpenaiEx.Files
# hr_file = OpenaiEx.new_file(path: Path.join(__DIR__, "../assets/cyberdyne.txt"))
hrf_url = "https://raw.githubusercontent.com/restlessronin/openai_ex/main/assets/cyberdyne.txt"
hr_file = OpenaiEx.new_file(name: hrf_url, content: fetch_blob.(hrf_url))
hr_upload_req = Files.new_upload(file: hr_file, purpose: "assistants")
{:ok, hr_upload_res} = openai |> Files.create(hr_upload_req)
file_id = hr_upload_res["id"]
Next we create the update request
math_assistant_req =
Assistants.new(
instructions:
"You are a personal math tutor. When asked a question, write and run Python code to answer the question.",
name: "Math Tutor",
tools: [%{type: "code_interpreter"}],
model: "gpt-4o-mini",
tool_resources: %{code_interpreter: %{file_ids: [file_id]}}
)
Finally we call the endpoint to modify the Assistant
{:ok, asst} = openai |> Assistants.update(assistant_id, math_assistant_req)
Delete Assistant
Finally we can delete assistants using the Assistant.delete()
function
openai |> Assistants.delete(assistant_id)
List Assistants
We use Assistant.list()
to get a list of assistants
assts = openai |> Assistants.list()
Thread
alias OpenaiEx.Beta.Threads
alias OpenaiEx.Beta.Threads.Messages
Create thread
Use the [Thread.create()
] function to create threads. A thread can be created empty or with messages.
{:ok, empty_thread} = openai |> Threads.create()
msg_hr =
Messages.new(
role: "user",
content: "What company do we work at?",
attachments: [%{file_id: file_id, tools: [%{type: "file_search"}]}]
)
msg_ai = Messages.new(role: "user", content: "How does AI work? Explain it in simple terms.")
thrd_req = Threads.new(messages: [msg_hr, msg_ai])
{:ok, thread} = openai |> Threads.create(thrd_req)
Retrieve thread
Thread.retrieve()
can be used to get the thread parameters given the id.
thread_id = thread["id"]
openai |> Threads.retrieve(thread_id)
Modify thread
The metadata for a thread can be modified using Thread.update()
openai |> Threads.update(thread_id, %{metadata: %{modified: "true", user: "abc123"}})
Delete thread
Use Thread.delete()
to delete a thread
openai |> Threads.delete(thread_id)
Verify deletion
openai |> Threads.retrieve(thread_id)
Messages
Create message
You can create a single message for a thread using Message.create()
thread_id = empty_thread["id"]
{:ok, message} = openai |> Threads.Messages.create(thread_id, msg_hr)
Retrieve message
Use [Message.retrieve()
] to retrieve a message
message_id = message["id"]
openai |> Threads.Messages.retrieve(%{thread_id: thread_id, message_id: message_id})
Modify message
The metadata for a message can be modified by [Message.update()
]
metadata = %{modified: "true", user: "abc123"}
upd_msg_req =
Threads.Messages.new(thread_id: thread_id, message_id: message_id, metadata: metadata)
{:ok, message} = openai |> Threads.Messages.update(upd_msg_req)
List messages
Use [Message.list()
] to get all the messages for a given thread
openai |> Threads.Messages.list(thread_id)
Runs
alias OpenaiEx.Beta.Threads.Runs
Create run
A run represents an execution on a thread. Use to Run.create()
with an assistant on a thread
{:ok, math_assistant} = openai |> Assistants.create(math_assistant_req)
math_assistant_id = math_assistant["id"]
run_req = Runs.new(thread_id: thread_id, assistant_id: math_assistant_id)
{:ok, run} = openai |> Runs.create(run_req)
Streaming
It is possible to stream the result of executing a run or resuming a run after submitting tool outputs. To accomplish this, pass stream: true
to the create
, create_thread_and_run
and submit_tool_outputs
functions.
{:ok, run_stream} = openai |> Runs.create(run_req, stream: true)
IO.puts(inspect(run_stream))
IO.puts(inspect(run_stream.task_pid))
run_stream.body_stream |> Stream.flat_map(& &1) |> Enum.each(fn x -> IO.puts(inspect(x)) end)
Retrieve run
Retrieve a run using Run.retrieve()
run_id = run["id"]
openai |> Runs.retrieve(%{thread_id: thread_id, run_id: run_id})
Modify run
The run metadata can be modified using the Run.update()
function
openai
|> Runs.update(%{
thread_id: thread_id,
run_id: run_id,
metadata: %{user_id: "user_zmVY6FvuBDDwIqM4KgH"}
})
List runs
List the runs belonging to a thread using Run.list()
# Basic usage
openai |> Runs.list([
thread_id: thread_id
])
# With optional parameters
openai |> Runs.list([
thread_id: thread_id,
limit: 10,
order: "desc",
include: ["run_steps"]
])
Submit tool outputs to a run
When a run has the status
: “requires_action” and required_action.type
is submit_tool_outputs
, the Run.submit_tool_outputs()
can be used to submit the outputs from the tool calls once they’re all completed. All outputs must be submitted in a single request.
openai
|> Runs.submit_tool_outputs(%{
thread_id: thread_id,
run_id: run_id,
tool_outputs: [%{tool_call_id: "foobar", output: "28C"}]
})
Cancel a run
You can cancel a run in_progress
using Run.cancel()
openai |> Runs.cancel(%{thread_id: thread_id, run_id: run_id})