defmodule Noizu.OpenAI.Api.Chat do
@moduledoc """
Noizu.OpenAI.Api.Chat is a module that provides functionality for handling chat-based interactions using
OpenAI's API.
This module offers one main function:
1. `chat/2` - Generates a chat-based completion using the given messages and options.
## Usage
{:ok, chat_response} = Noizu.OpenAI.Api.Chat.chat(messages, options)
"""
require Noizu.OpenAI
import Noizu.OpenAI
#-------------------------------
#
#-------------------------------
@doc """
Generates a chat-based completion using the OpenAI API.
## Parameters
- messages: A list of maps containing message role and content
- options: An optional map or keyword list containing API options
## Returns
Returns a tuple {:ok, response} on successful API call, where response is a map containing the chat response.
Returns {:error, term} on failure, where term contains error details.
## Example
messages = [
%{"role" => "system", "content" => "You are a helpful assistant."},
%{"role" => "user", "content" => "Who won the world series in 2020?"}
]
{:ok, response} = Noizu.OpenAI.Api.Chat.chat(messages)
"""
@type chat_response() :: map()
@type chat_supported_models() :: :"gpt-3.5-turbo" | :gpt4 | atom
@type chat_options() :: %{
optional(:model) => Noizu.OpenAI.model_option(chat_supported_models()),
optional(:temperature) => Noizu.OpenAI.temperature_option(),
optional(:top_p) => Noizu.OpenAI.top_p_option(),
optional(:completions | :n) => Noizu.OpenAI.completions_option(),
optional(:stream) => Noizu.OpenAI.stream_option(),
optional(:seed) => any,
optional(:stop) => Noizu.OpenAI.stop_option(),
optional(:max_tokens) => Noizu.OpenAI.max_tokens_option(),
optional(:presence_penalty) => Noizu.OpenAI.presence_penalty_option(),
optional(:logit_bias) => Noizu.OpenAI.logit_bias_option(),
optional(:user) => Noizu.OpenAI.user_option(),
} | Keyword.t()
@type chat_message :: %{:role => String.t, :message => String.t}
@spec chat(messages :: list(chat_message), options :: chat_options()) :: {:ok, chat_response()} | {:error, term}
def chat(messages, options \\ nil) do
url = openai_base() <> "chat/completions"
body = %{messages: messages}
|> put_field(:model, options, Application.get_env(:noizu_openai, :default_chat_model, "gpt-3.5-turbo"))
|> put_field(:temperature, options)
|> put_field(:top_p, options)
|> put_field({:completions, :n}, options)
|> put_field(:stream, options, false)
|> put_field(:stop, options)
|> put_field(:seed, options)
|> put_field(:response_format, options)
|> put_field(:functions, options)
|> put_field(:function_call, options)
|> put_field(:tools, options)
|> put_field(:tool_choice, options)
|> put_field(:max_tokens, options)
|> put_field(:frequency_penalty, options)
|> put_field(:presence_penalty, options)
|> put_field(:logit_bias, options)
|> put_field(:user, options)
case api_call(:post, url, body, Noizu.OpenAI.Chat, options) do
response = {:ok, _} -> response
error ->
cond do
options[:retry] == true -> chat(messages, put_in(options, [:retry], 3))
is_integer(options[:retry]) && options[:retry] > 1 -> chat(messages, put_in(options, [:retry], options[:retry] - 1))
:else -> error
end
end
end
end