Packages
Execute Python applications from Erlang using dirty NIFs
Retired package: Release invalid - Missing priv/erlang_loop.py
Current section
Files
Jump to
Current section
Files
examples/ai_chat.erl
#!/usr/bin/env escript
%%% @doc AI Chat example - interactive conversation with an LLM.
%%%
%%% This example demonstrates:
%%% - Connecting to local Ollama or OpenAI API
%%% - Maintaining conversation history
%%% - Interactive chat loop
%%%
%%% Prerequisites:
%%% 1. Build the project: rebar3 compile
%%% 2. Create a venv:
%%% python3.14 -m venv /tmp/ai-venv
%%% /tmp/ai-venv/bin/pip install requests
%%%
%%% For Ollama (recommended, free, local):
%%% - Install: https://ollama.ai
%%% - Run: ollama pull llama3.2
%%%
%%% For OpenAI:
%%% - Set OPENAI_API_KEY environment variable
%%% - pip install openai
%%%
%%% Run from project root:
%%% escript examples/ai_chat.erl
-mode(compile).
main(Args) ->
setup_paths(),
{ok, _} = application:ensure_all_started(erlang_python),
io:format("~n=== AI Chat Example ===~n~n"),
VenvPath = case Args of
[Path | _] -> Path;
[] -> "/tmp/ai-venv"
end,
case activate_venv(VenvPath) of
ok -> ok;
error -> halt(1)
end,
%% Initialize chat
io:format("Initializing chat system...~n"),
ok = init_ai_helpers(),
{ok, LLMType} = get_llm_type(),
case LLMType of
<<"none">> ->
io:format("~nNo LLM available!~n~n"),
io:format("Setup options:~n"),
io:format(" 1. Install Ollama: https://ollama.ai~n"),
io:format(" Then run: ollama pull llama3.2~n~n"),
io:format(" 2. Set OPENAI_API_KEY environment variable~n"),
io:format(" And: pip install openai~n~n"),
cleanup(),
halt(1);
_ ->
io:format("Using LLM: ~s~n~n", [LLMType]),
io:format("Type your messages (or 'quit' to exit, 'clear' to reset)~n"),
io:format("---------------------------------------------------~n~n"),
chat_loop([])
end.
setup_paths() ->
ScriptDir = filename:dirname(escript:script_name()),
ProjectRoot = filename:dirname(ScriptDir),
EbinDir = filename:join([ProjectRoot, "_build", "default", "lib", "erlang_python", "ebin"]),
true = code:add_pathz(EbinDir).
activate_venv(VenvPath) ->
io:format("Activating venv: ~s~n", [VenvPath]),
case py:activate_venv(list_to_binary(VenvPath)) of
ok ->
ok;
{error, VenvError} ->
io:format("Error: ~p~n", [VenvError]),
io:format("~nSetup: python3.14 -m venv ~s && ~s/bin/pip install requests~n~n",
[VenvPath, VenvPath]),
error
end.
init_ai_helpers() ->
%% Add examples directory to Python path
ScriptDir = filename:dirname(escript:script_name()),
ProjectRoot = filename:dirname(ScriptDir),
ExamplesDir = list_to_binary(filename:join(ProjectRoot, "examples")),
{ok, _} = py:eval(<<"(__import__('sys').path.insert(0, path) if path not in __import__('sys').path else None, True)[1]">>, #{path => ExamplesDir}),
ok.
get_llm_type() ->
py:call(ai_helpers, get_llm_type, []).
chat_loop(History) ->
case io:get_line("You: ") of
eof ->
io:format("~nGoodbye!~n"),
cleanup();
{error, _} ->
io:format("~nGoodbye!~n"),
cleanup();
Line ->
Input = string:trim(Line),
case string:lowercase(Input) of
"quit" ->
io:format("~nGoodbye!~n"),
cleanup();
"clear" ->
io:format("~n[Conversation cleared]~n~n"),
chat_loop([]);
"" ->
chat_loop(History);
_ ->
%% Add user message to history
UserMsg = #{role => <<"user">>, content => list_to_binary(Input)},
NewHistory = History ++ [UserMsg],
%% Get response
io:format("~nAssistant: "),
{ok, Response} = py:call(ai_helpers, chat, [NewHistory]),
io:format("~s~n~n", [Response]),
%% Add assistant message to history
AssistantMsg = #{role => <<"assistant">>, content => Response},
chat_loop(NewHistory ++ [AssistantMsg])
end
end.
cleanup() ->
ok = py:deactivate_venv(),
ok = application:stop(erlang_python).