Packages
fnord
0.5.9
0.9.40
0.9.39
0.9.38
0.9.37
0.9.36
0.9.35
0.9.34
0.9.33
0.9.32
0.9.31
0.9.30
0.9.29
0.9.28
0.9.27
0.9.26
0.9.25
0.9.24
0.9.23
0.9.22
0.9.21
0.9.20
0.9.19
0.9.18
0.9.17
0.9.16
0.9.15
0.9.14
0.9.13
0.9.12
0.9.11
0.9.10
0.9.9
0.9.8
0.9.7
0.9.6
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.99
0.8.98
0.8.97
0.8.96
0.8.95
0.8.94
0.8.93
0.8.92
0.8.91
0.8.90
0.8.89
0.8.88
0.8.87
0.8.86
0.8.85
0.8.84
0.8.83
0.8.82
0.8.81
0.8.80
0.8.79
0.8.78
0.8.77
0.8.76
0.8.75
0.8.74
0.8.73
0.8.72
0.8.71
0.8.70
0.8.69
0.8.68
0.8.67
0.8.66
0.8.65
0.8.64
0.8.63
0.8.62
0.8.61
0.8.60
0.8.59
0.8.58
0.8.57
0.8.56
0.8.55
0.8.54
0.8.53
0.8.52
0.8.51
0.8.50
0.8.49
0.8.48
0.8.47
0.8.46
0.8.45
0.8.44
0.8.43
0.8.42
0.8.41
0.8.40
0.8.39
0.8.38
0.8.37
0.8.36
0.8.35
0.8.34
0.8.33
0.8.32
0.8.31
0.8.30
0.8.29
0.8.27
0.8.26
0.8.25
0.8.24
0.8.23
0.8.22
0.8.21
0.8.20
0.8.19
0.8.18
0.8.17
0.8.16
0.8.15
0.8.14
0.8.13
0.8.12
0.8.11
0.8.1
0.8.0
0.7.24
0.7.23
0.7.22
0.7.21
0.7.20
0.7.19
0.7.18
0.7.17
0.7.16
0.7.15
0.7.14
0.7.13
0.7.12
0.7.11
0.7.10
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.3
0.7.2
0.7.1
0.7.0
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.1
0.6.0
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.44
0.4.43
0.4.42
0.4.41
0.4.40
0.4.39
0.4.38
0.4.37
0.4.36
0.4.35
0.4.34
0.4.33
0.4.32
0.4.30
0.4.29
0.4.28
0.4.27
0.4.26
0.4.25
0.4.24
0.4.23
0.4.22
0.4.21
0.4.20
0.4.19
0.4.18
0.4.17
0.4.16
0.4.15
0.4.14
0.4.13
0.4.12
0.4.11
0.4.10
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.0
0.2.0
0.1.0
AI code archaeology
Current section
Files
Jump to
Current section
Files
lib/ai/openai.ex
defmodule AI.OpenAI do
@moduledoc """
This module provides functions to interact with the OpenAI API, including
getting embeddings and completions.
"""
@api_key_error "Missing OpenAI API key. Please set the OPENAI_API_KEY environment variable."
@embedding_endpoint "https://api.openai.com/v1/embeddings"
@completion_endpoint "https://api.openai.com/v1/chat/completions"
defstruct [
:api_key,
:http_options
]
def new(http_options) do
workers = Application.get_env(:fnord, :workers, Cmd.default_workers())
%__MODULE__{
api_key: get_api_key(),
http_options:
[hackney_options: [pool: :openai, max_connections: workers]]
|> Keyword.merge(http_options)
}
end
def get_embedding(openai, model, input) do
headers = [get_auth_header(openai)]
payload = %{model: model, encoding_format: "float", input: input}
Http.post_json(@embedding_endpoint, headers, payload, openai.http_options)
|> case do
{:ok, %{"data" => [%{"embedding" => embedding}]}} -> {:ok, embedding}
{:error, error} -> {:error, error}
end
end
def get_completion(openai, model, msgs, tools \\ nil) do
headers = [get_auth_header(openai)]
payload =
case tools do
nil -> %{model: model, messages: msgs}
tools -> %{model: model, messages: msgs, tools: tools}
end
Http.post_json(@completion_endpoint, headers, payload, openai.http_options)
|> case do
{:ok, response} -> get_completion_response(response)
{:error, error} -> get_error_response(error)
end
end
# -----------------------------------------------------------------------------
# Private functions
# -----------------------------------------------------------------------------
defp get_api_key() do
case System.get_env("OPENAI_API_KEY", nil) do
nil -> raise @api_key_error
api_key -> api_key
end
end
defp get_auth_header(openai) do
{"Authorization", "Bearer #{openai.api_key}"}
end
defp get_completion_response(%{"choices" => [%{"message" => response}]}) do
get_completion_response(response)
end
defp get_completion_response(%{"tool_calls" => tool_calls}) do
{:ok, :tool, Enum.map(tool_calls, &get_tool_call/1)}
end
defp get_completion_response(%{"content" => response}) do
{:ok, :msg, response}
end
defp get_tool_call(%{"id" => id, "function" => %{"name" => name, "arguments" => args}}) do
%{id: id, function: %{name: name, arguments: args}}
end
defp get_error_response(:closed), do: {:error, "Connection closed"}
defp get_error_response({http_status, json_error_string}) do
json_error_string
|> Jason.decode()
|> case do
{:ok, %{"error" => %{"code" => code, "message" => msg}}} ->
{:error, %{http_status: http_status, code: code, message: msg}}
{:ok, error} ->
{:error, %{http_status: http_status, error: inspect(error, pretty: true)}}
{:error, _} ->
{:error, %{http_status: http_status, error: json_error_string}}
end
end
end