Current section
Files
Jump to
Current section
Files
lib/tangram.ex
defmodule Tangram do
@moduledoc """
"""
defmodule Model do
@moduledoc """
"""
defstruct [
:model,
:log_queue,
:tangram_url
]
end
defmodule ModelOptions do
@moduledoc """
"""
defstruct [
:tangram_url
]
end
defmodule PredictOptions do
@moduledoc """
"""
@derive Jason.Encoder
defstruct [
:threshold,
:compute_feature_contributions
]
end
defmodule LogPredictionArgs do
@moduledoc """
"""
@derive Jason.Encoder
defstruct [
:identifier,
:input,
:options,
:output
]
end
defmodule LogTrueValueArgs do
@moduledoc """
"""
@derive Jason.Encoder
defstruct [
:identifier,
:true_value
]
end
defmodule LogPredictionEvent do
@moduledoc """
"""
@derive Jason.Encoder
defstruct [
:type,
:model_id,
:date,
:identifier,
:input,
:options,
:output
]
end
defmodule LogTrueValueEvent do
@moduledoc """
"""
@derive Jason.Encoder
defstruct [
:type,
:model_id,
:date,
:identifier,
:true_value
]
end
@on_load {:init, 0}
def init do
sys_arch = to_string(:erlang.system_info(:system_architecture))
nif_path =
cond do
String.match?(sys_arch, ~r/x86_64-(pc|unknown)-linux-gnu/) ->
"x86_64-unknown-linux-gnu/libtangram_elixir"
# String.match?(sys_arch, ~r/(aarch64|arm)-(pc|unknown)-linux-gnu/) ->
# "aarch64-unknown-linux-gnu/libtangram_elixir"
String.match?(sys_arch, ~r/x86_64-(alpine|pc)-linux-musl/) ->
"x86_64-unknown-linux-gnu/libtangram_elixir"
# String.match?(sys_arch, ~r/aarch64-(alpine|pc)-linux-musl/) ->
# "aarch64-unknown-linux-gnu/libtangram_elixir"
String.match?(sys_arch, ~r/x86_64-apple-darwin[0-9]+\.[0-9]+\.[0-9]+/) ->
"x86_64-apple-darwin/libtangram_elixir"
# String.match?(sys_arch, ~r/(aarch64|arm)-apple-darwin[0-9]+\.[0-9]+\.[0-9]+/) ->
# "aarch64-apple-darwin/libtangram_elixir"
true ->
raise "Tangram for Elixir does not yet support your combination of operating system and CPU architecture. Open an issue at https://github.com/tangramxyz/tangram/issues/new or email us at help@tangram.xyz to complain."
end
path = :filename.join(:code.priv_dir(:tangram), nif_path)
:ok = :erlang.load_nif(path, 0)
end
@doc """
"""
def load_model(data, options \\ nil) do
model = _load_model(data)
tangram_url = if options, do: options.tangram_url, else: "https://app.tangram.xyz"
%Model{
model: model,
log_queue: [],
tangram_url: tangram_url
}
end
@doc """
"""
def load_model_from_file(path, options \\ nil) do
data = File.read!(path)
load_model(data, options)
end
@doc """
"""
def predict(model, input, options \\ nil) do
_predict(model.model, input, options)
end
@doc """
"""
def log_prediction(model, args) do
event = prediction_event(model, args)
log_events(model.tangram_url, event)
end
@doc """
"""
def log_true_value(model, args) do
event = true_value_event(model, args)
log_events(model.tangram_url, event)
end
@doc """
"""
def enqueue_log_prediction(model, args) do
event = prediction_event(model, args)
%{model | log_queue: model.log_queue ++ [event]}
end
@doc """
"""
def enqueue_log_true_value(model, args) do
event = true_value_event(model, args)
%{model | log_queue: model.log_queue ++ [event]}
end
@doc """
"""
def flush_log_queue(model) do
log_events(model.tangram_url, model.log_queue)
%{model | log_queue: []}
end
def log_events(tangram_url, events) do
url = tangram_url <> "/track"
headers = %{"Content-Type": "application/json"}
body = Jason.encode!(events)
HTTPoison.post!(url, body, headers)
end
def prediction_event(model, args) do
model_id = _model_id(model.model)
%LogPredictionEvent{
type: "prediction",
model_id: model_id,
date: DateTime.utc_now() |> DateTime.to_iso8601(),
identifier: args.identifier,
options: args.options,
input: args.input,
output: args.output
}
end
def true_value_event(model, args) do
model_id = _model_id(model.model)
%LogTrueValueEvent{
type: "true_value",
model_id: model_id,
date: DateTime.utc_now() |> DateTime.to_iso8601(),
identifier: args.identifier,
true_value: args.true_value
}
end
def _load_model(_) do
:erlang.nif_error(:nif_not_loaded)
end
def _model_id(_) do
:erlang.nif_error(:nif_not_loaded)
end
def _predict(_, _, _) do
:erlang.nif_error(:nif_not_loaded)
end
end