Packages

Generative AI Wrapper: access multiple apis through single standardized interface.

Current section

Files

Jump to
genai lib gen_ai chat.ex
Raw

lib/gen_ai/chat.ex

defmodule GenAI.Settings do
@moduledoc """
This module defines the settings struct used to configure GenAI interactions.
"""
@vsn 1.0
defstruct [
model: [],
api_key: %{},
api_org: %{},
hyper_params: [],
tools: [],
vsn: @vsn
]
defimpl GenAIProtocol do
@moduledoc """
Implements the `GenAIProtocol` for `GenAI.Settings`.
This allows settings to be used as a context for configuring GenAI interactions.
"""
def with_model(context, model) do
%{context | model: [model | context.model]}
end
def with_tool(context, tool) do
%{context | tools: [tool | context.tools]}
end
def with_tools(context, tools) do
%{context | tools: tools ++ context.tools}
end
def with_api_key(context, provider, api_key) do
%{context | api_key: Map.put(context.api_key, provider, api_key)}
end
def with_api_org(context, provider, api_org) do
%{context | api_org: Map.put(context.api_org, provider, api_org)}
end
def with_setting(context, setting, value) do
%{context | hyper_params: [{setting, value} | context.hyper_params]}
end
def with_safety_setting(context, safety_setting, threshold) do
%{context | hyper_params: [ {:safety_setting, %{category: safety_setting, threshold: threshold}} | context.hyper_params]}
end
# Messages are not stored in settings, so these functions simply return the context unchanged.
def with_message(context, _message), do: context
def with_messages(context, _messages), do: context
# Settings do not support streaming or direct inference execution.
def stream(_, _), do: {:error, {:unsupported, GenAI.Settings}}
def run(_), do: {:error, {:unsupported, GenAI.Settings}}
end
end
defmodule GenAI.Chat do
@moduledoc """
This module defines the chat struct used to manage conversations with generative AI models.
"""
@vsn 1.0
defstruct [
settings: %GenAI.Settings{},
messages: [],
vsn: @vsn
]
defimpl GenAIProtocol do
@moduledoc """
Implements the `GenAIProtocol` for `GenAI.Chat`.
This allows chat contexts to be used for configuring and running GenAI interactions.
"""
# Delegate setting functions to the settings struct.
def with_model(context, model) do
%{context | settings: GenAIProtocol.with_model(context.settings, model)}
end
def with_tool(context, tool) do
%{context | settings: GenAIProtocol.with_tool(context.settings, tool)}
end
def with_tools(context, tools) do
%{context | settings: GenAIProtocol.with_tools(context.settings, tools)}
end
def with_api_key(context, provider, api_key) do
%{context | settings: GenAIProtocol.with_api_key(context.settings, provider, api_key)}
end
def with_api_org(context, provider, api_org) do
%{context | settings: GenAIProtocol.with_api_org(context.settings, provider, api_org)}
end
def with_setting(context, setting, value) do
%{context | settings: GenAIProtocol.with_setting(context.settings, setting, value)}
end
def with_safety_setting(context, safety_setting, threshold) do
%{context | settings: GenAIProtocol.with_safety_setting(context.settings, safety_setting, threshold)}
end
def with_message(context, message) do
%{context | messages: [message | context.messages]}
end
def with_messages(context, messages) do
%{context | messages: Enum.reverse(messages) ++ context.messages}
end
def stream(_context, _handler) do
{:ok, :nyi}
end
@doc """
Runs inference on the chat context.
This function determines the final settings and model, prepares the messages, and then delegates the actual inference execution to the selected provider's `chat/3` function.
"""
def run(context) do
# Logic to pick/determine final set of settings, models, messages, with RAG/summarization.
model = hd(context.settings.model)
apply(model.provider, :chat, [context.messages, context.settings.tools, [{:model, model.model} | (context.settings.hyper_params)]])
end
end
end