AiFlow.Ollama.Chat (AiFlow v0.1.0)
View SourceHandles chat interactions with the Ollama API and manages conversation history.
This module allows sending messages to Ollama chat models and automatically maintains a persistent chat history. It supports various options for customizing requests and responses.
Features
- Automatic chat history persistence (JSON file)
- Conversation management by
chat_idanduser_id - Automatic model pulling when a model is not found
- Support for standard and raising (
!) function variants - Configurable response formatting with
:shortand:fieldoptions - Debug logging
Examples
# Simple chat interaction
{:ok, response} = AiFlow.Ollama.Chat.chat("Hello!", "my_chat", "user1")
# Get full API response
{:ok, full_response} = AiFlow.Ollama.Chat.chat("Hello!", "my_chat", "user1", short: false)
# Extract specific field from API response
{:ok, model_name} = AiFlow.Ollama.Chat.chat("Hello!", "my_chat", "user1", short: false, field: "model")
# Extract specific field from message object
{:ok, role} = AiFlow.Ollama.Chat.chat("Hello!", "my_chat", "user1", field: "role")
# Use a specific model
{:ok, response} = AiFlow.Ollama.Chat.chat("Bonjour!", "french_chat", "user1", model: "mistral")
# Enable debug logging
{:ok, response} = AiFlow.Ollama.Chat.chat("Debug me", "debug_chat", debug: true)
# View chat history
{:ok, history} = AiFlow.Ollama.Chat.show_chat_history("my_chat", "user1")
# Raise on error instead of returning {:error, ...}
response = AiFlow.Ollama.Chat.chat!("Hello!", "my_chat", "user1")
Summary
Functions
Sends a chat message to the Ollama API and stores the conversation in the chat history.
Same as chat/4, but raises a RuntimeError if the request fails instead of returning an error tuple.
Checks the integrity and format of the chat data file {It will be deprecated later =)}
Clears chat history based on provided options.
Clears chat history based on provided options.
Loads the raw chat data from the configured file and converts its keys to atoms for easier debugging.
Retrieves and returns the message history for a specific chat and user, intended for debugging purposes.
Retrieves all stored chat data.
Retrieves all stored chat data, raising on error.
Retrieves the chat history or list of chats for a specific user.
Retrieves the chat history or list of chats for a specific user, raising on error.
Functions
@spec chat(String.t(), String.t(), String.t(), keyword()) :: {:ok, term()} | {:error, AiFlow.Ollama.Error.t()}
Sends a chat message to the Ollama API and stores the conversation in the chat history.
Parameters
prompt: The user's message (string).chat_id: Unique identifier for the chat session (string).user_id: Identifier for the user (string, defaults to"default_user").opts: Keyword list of options::model(string): The Ollama model to use (defaults to config model).:debug(boolean): Iftrue, logs request/response details (defaults tofalse).:short(boolean): Controls response format.true(default): Returns the assistant's message content or the value of:fieldif specified.false: Returns the full Ollama API response map.
:field(string): Specifies a field to extract from the response.- If
short: true(default): Extracts the field from themessageobject (e.g.,"role","content"). If the field is not found inmessage, it attempts to find it at the top level of the response. - If
short: false: Extracts the field from the top-level API response (e.g.,"model","total_duration").
- If
- Other options are passed to the Ollama API (e.g.,
temperature,max_tokens).
Returns
{:ok, response}: The formatted response based on:shortand:fieldoptions.{:error, Error.t()}: An error with a reason (e.g., API failure, invalid response format).
Examples
# Send a message and get the response content (default behavior)
iex> AiFlow.Ollama.Chat.chat("Hello!", "chat123", "usr1")
{:ok, "Hi there! How can I help you today?"}
# Send a message with debug logging
iex> AiFlow.Ollama.Chat.chat("What's the weather?", "chat123", "usr1", debug: true)
12:00:00.000 [debug] Sending request to http://localhost:11434/api/chat
12:00:00.000 [debug] Request body: %{"messages" => [%{"content" => "What's the weather?", "role" => "user"}], "model" => "llama3.1", "stream" => false}
12:00:00.000 [debug] Ollama chat response: Status=200, Body=%{"model" => "llama3.1", "message" => %{"role" => "assistant", "content" => "It's sunny!"}, "done" => true}
{:ok, "It's sunny!"}
# Get the full API response
iex> AiFlow.Ollama.Chat.chat("Hello!", "chat123", "usr1", short: false)
{:ok, %{"model" => "llama3.1", "message" => %{"role" => "assistant", "content" => "Hi there!"}, "done" => true, "total_duration" => 123456789}}
# Extract a specific field from the message object (default short: true)
iex> AiFlow.Ollama.Chat.chat("Hello!", "chat123", "usr1", field: {:body, "model"})
{:ok, "llama3.1"}
# Extract a specific field from the message object (default short: true)
iex> AiFlow.Ollama.Chat.chat("Hello!", "chat123", "usr1", field: {:body, ["message", "role"]})
{:ok, "assistant"}
# Handle an API error
iex> AiFlow.Ollama.Chat.chat("Hi", "chat123", "usr1")
{:error, %AiFlow.Ollama.Error{type: :unknown, reason: "Connection timeout"}}
Same as chat/4, but raises a RuntimeError if the request fails instead of returning an error tuple.
Parameters
- Same as
chat/4.
Returns
String.t(): Assistant Answer.term(): The processed response based on:shortand:fieldoptions.Error.t(): An error struct if the request fails.
Raises
RuntimeErrorif the chat request fails or the chat data cannot be loaded/saved.
Examples
# Successful chat
iex> AiFlow.Ollama.Chat.chat!("Hello!", "chat123", "usr1")
"Hi there!"
# Raises on error
iex> AiFlow.Ollama.Chat.chat!("Hi", "chat123", "usr1")
** (RuntimeError) Chat request failed: %AiFlow.Ollama.Error{type: :unknown, reason: "Connection timeout"}
@spec check_chat_file() :: {:ok, map()} | {:error, AiFlow.Ollama.Error.t()}
Checks the integrity and format of the chat data file {It will be deprecated later =)}
Returns
{:ok, map()}: The parsed chat data if the file is valid.{:error, Error.t()}: An error if the file is missing or malformed.
@spec clear_chat_history(keyword()) :: {:ok, :deleted} | {:error, AiFlow.Ollama.Error.t()}
@spec clear_chat_history(keyword()) :: {:ok, :deleted} | {:error, AiFlow.Ollama.Error.t()}
Clears chat history based on provided options.
Options
:confirm(boolean): Must betrueto proceed with deletion (defaults tofalse).:user_id(string): The user ID whose chats to delete (optional).:chat_id(string): The specific chat ID to delete (requires:user, optional).
Returns
{:ok, :success}: Confirmation of deletion.{:ok, :deleted}: If selected chat has already been deleted{:error, Error.t()}: An error if deletion failed or confirmation was not given.
Examples
# Delete all chat without confirm: true
AiFlow.Ollama.Chat.clear_chat_history()
{:error, "Please confirm deletion of all chats by passing 'confirm: true' as an option."}
# Delete all chat with confirm: true
AiFlow.Ollama.Chat.clear_chat_history(confirm: true)
{:ok, :success}
# Delete user chat without chat_id
AiFlow.Ollama.Chat.clear_chat_history(user_id: "user1")
{:error, "Please confirm deletion of all chats for user 'user1' by passing 'confirm: true' as an option, or specify a chat ID with 'chat: chat_id' to delete a specific chat."}
# Delete user chat
AiFlow.Ollama.Chat.clear_chat_history(chat_id: "my_chat", user_id: "user1")
{:ok, :success}
# If the selected chat has already been deleted
AiFlow.Ollama.Chat.clear_chat_history(chat_id: "my_chat", user_id: "user1")
{:ok, :deleted}
Clears chat history based on provided options.
Options
:confirm(boolean): Must betrueto proceed with deletion (defaults tofalse).:user_id(string): The user ID whose chats to delete (optional).:chat_id(string): The specific chat ID to delete (requires:user, optional).
Returns
{:ok, :success}: Confirmation of deletion.{:ok, :deleted}: If selected chat has already been deleted{:error, Error.t()}: An error if deletion failed or confirmation was not given.
Examples
# Delete all chat without confirm: true
AiFlow.Ollama.Chat.clear_chat_history!()
"Please confirm deletion of all chats by passing 'confirm: true' as an option."
# Delete user chat
AiFlow.Ollama.Chat.clear_chat_history!(chat_id: "my_chat", user_id: "user1")
:success
# If the selected chat has already been deleted
AiFlow.Ollama.Chat.clear_chat_history!(chat_id: "my_chat", user_id: "user1")
:deleted
@spec debug_load_chat_data() :: {:ok, map()} | {:error, AiFlow.Ollama.Error.t()}
Loads the raw chat data from the configured file and converts its keys to atoms for easier debugging.
This function is intended for debugging purposes. It reads the chat data file specified in the
configuration, parses the JSON content, and then recursively converts all string keys in the
resulting map to atom keys. This can make the data structure easier to inspect and work with
in an interactive debugging session (e.g., in iex).
Returns
{:ok, map()}: A map representing the chat data with atom keys.{:error, Error.t()}: An error reason if the file could not be read or parsed.
Examples
# In a successful case, loads and atomizes the chat data
iex> AiFlow.Ollama.Chat.debug_load_chat_data()
{:ok,
%{
chats: %{
"default_user" => %{
"my_chat" => %{
"created_at" => "2023-10-27T10:00:00Z",
"messages" => [
%{"content" => "Hello", "role" => "user", "timestamp" => "2023-10-27T10:00:01Z"},
%{"content" => "Hi there!", "role" => "assistant", "timestamp" => "2023-10-27T10:00:02Z"}
],
"model" => "llama3.1",
"name" => "my_chat",
"updated_at" => "2023-10-27T10:00:02Z"
}
}
},
created_at: "2023-10-27T10:00:00Z"
}}
# In an error case (e.g., file not found or invalid JSON)
iex> # Assuming the chat file is corrupted
iex> AiFlow.Ollama.Chat.debug_load_chat_data()
{:error, %Jason.DecodeError{data: "<<", position: 0, token: nil}}
Retrieves and returns the message history for a specific chat and user, intended for debugging purposes.
This function directly fetches the list of messages associated with a given chat ID and user ID from the chat data file. It's a simplified way to inspect the raw message history without any additional processing or error wrapping, making it useful for debugging chat state or history issues.
Parameters
chat_id: The unique identifier of the chat session (string).user_id: The identifier of the user (string, defaults to"default_user").
Returns
list(): A list of message maps (e.g.,[ %{"role" => "user", "content" => "...", ...}, ...]) belonging to the specified chat and user. Returns an empty list[]if the chat/user is not found or if there's an error loading the chat data.
Examples
# Retrieve messages for an existing chat
iex> AiFlow.Ollama.Chat.debug_show_chat_history("my_chat", "user1")
[
%{"role" => "user", "content" => "Hello!", "timestamp" => "2023-10-27T10:00:00Z"},
%{"role" => "assistant", "content" => "Hi there!", "timestamp" => "2023-10-27T10:00:01Z"}
]
# Retrieve messages for a non-existent chat (returns empty list)
iex> AiFlow.Ollama.Chat.debug_show_chat_history("unknown_chat", "user1")
[]
# Retrieve messages using the default user ID
iex> AiFlow.Ollama.Chat.debug_show_chat_history("default_chat")
[%{"role" => "user", "content" => "Default user message", ...}]
# If there's an error loading the chat file (e.g., corrupt JSON), it logs the error and returns []
# (Assuming the chat file is corrupted)
iex> AiFlow.Ollama.Chat.debug_show_chat_history("any_chat")
# 12:00:00.000 [error] Failed to load chat data for debug: %Jason.DecodeError{...}
[]
@spec show_all_chats() :: {:ok, map()} | {:error, AiFlow.Ollama.Error.t()}
Retrieves all stored chat data.
Returns
{:ok, map()}: The entire chat data map with atom keys.{:error, Error.t()}: An error if the chat data could not be loaded.
@spec show_all_chats!() :: map() | AiFlow.Ollama.Error.t()
Retrieves all stored chat data, raising on error.
Returns
map(): The entire chat data map with atom keys.Error.t(): An error if the chat data could not be loaded.
Raises
RuntimeErrorif the chat data could not be loaded.
@spec show_chat_history(keyword()) :: {:ok, term()} | {:error, AiFlow.Ollama.Error.t()}
Retrieves the chat history or list of chats for a specific user.
Parameters
opts: Keyword list of options:user_id: The ID of the user (string).chat_id: The ID of a specific chat to retrieve (string, optional).:short(boolean): Controls the response format.true(default): Returns a list of chat names/IDs for the user (ifchat_idis nil), or the content (list of messages) of the specific chat (ifchat_idis provided).false: Returns the full map(s) of chat data. Ifchat_idis nil, returns a map of all user's chats. Ifchat_idis provided, returns the full map of that specific chat.
Returns
{:ok, term()}: The requested data based onuser_id,chat_id, and:shortoption.{:error, Error.t()}: An error if the chat data could not be loaded or chat is not found.
Examples
# Get all users in short: true version
iex> AiFlow.Ollama.show_chat_history()
{:ok, %{users: ["default_user"]}}
# Get all users in short: false version
iex> AiFlow.Ollama.show_chat_history()
{:ok, %{users: ["default_user"]}}
iex(41)> AiFlow.Ollama.show_chat_history(short: false)
{:ok, %{"chats" => %{"default_user" => %{...}}2
# Get list of chat names for a user (short: true by default)
iex> AiFlow.Ollama.Chat.show_chat_history(user_id: "user1")
{:ok, ["chat1", "chat2"]}
# Get full map of all chats for a user
iex> AiFlow.Ollama.Chat.show_chat_history(user_id: "user1", short: false)
{:ok, %{"chat1" => %{"name" => "chat1", "messages" => [...], ...}, "chat2" => %{...}}}
# Get messages list for a specific chat (short: true by default)
iex> AiFlow.Ollama.Chat.show_chat_history(user_id: "user1", chat_id: "chat1")
{:ok, [%{"role" => "user", "content" => "..."}, %{"role" => "assistant", "content" => "..."}]}
# Get full map for a specific chat
iex> AiFlow.Ollama.Chat.show_chat_history(user_id: "user1", chat_id: "chat1", short: false)
{:ok, %{"name" => "chat1", "messages" => [...], "created_at" => "...", ...}}
# Handle user not found or no chats
iex> AiFlow.Ollama.Chat.show_chat_history(user_id: "unknown_user")
{:ok, []}
# Handle specific chat not found
iex> AiFlow.Ollama.Chat.show_chat_history(user_id: "user1", chat_id: "unknown_chat")
{:error, :chat_not_found}
@spec show_chat_history!(keyword()) :: term() | AiFlow.Ollama.Error.t()
Retrieves the chat history or list of chats for a specific user, raising on error.
Parameters
opts: Keyword list of options:user_id: The ID of the user (string).chat_id: The ID of a specific chat to retrieve (string, optional).:short(boolean): Controls the response format.true(default): Returns a list of chat names/IDs for the user (ifchat_idis nil), or the content (list of messages) of the specific chat (ifchat_idis provided).false: Returns the full map(s) of chat data. Ifchat_idis nil, returns a map of all user's chats. Ifchat_idis provided, returns the full map of that specific chat.
Returns
term(): The requested data based onuser_id,chat_id, and:shortoption.Error.t(): An error if the chat data could not be loaded or chat is not found.
Raises
RuntimeErrorif the chat data could not be loaded or chat is not found.
Examples
# Get list of chat names for a user
iex> AiFlow.Ollama.Chat.show_chat_history!(user_id: "user1")
["chat1", "chat2"]
# Get messages list for a specific chat
iex> AiFlow.Ollama.Chat.show_chat_history!(user_id: "user1", chat_id: "chat1")
[%{"role" => "user", "content" => "..."}, ...]
# Raises on error
iex> AiFlow.Ollama.Chat.show_chat_history!(user_id: "unknown_user", chat_id: "unknown_chat")
** (RuntimeError) Failed to show chat history: :chat_not_found