Mix.install([
{:typesafe_api, "~> 0.1.0-alpha.3"}
])Client
The client reads TYPESAFE_API_KEY from the environment. If Livebook was launched from the
Dock it will not see your zshrc, so it also falls back to a Livebook secret named
TYPESAFE_API_KEY (exposed as LB_TYPESAFE_API_KEY).
api_key = System.get_env("TYPESAFE_API_KEY") || System.fetch_env!("LB_TYPESAFE_API_KEY")
client = TypeSafeAPI.new(api_key: api_key)The question set
Three question types, one state. Keys are atoms and round-trip back as atoms.
state = "Help! My payouts have been failing for 3 days."
questions = [
urgent: TypeSafeAPI.noul("Does this convey urgency?"),
dept:
TypeSafeAPI.choice("Which team should handle this?",
billing: "Payments, invoicing, refunds",
technical: "Bugs, outages, integrations",
sales: nil
),
anger: TypeSafeAPI.score("How frustrated is the customer?", ["Calm", "Frustrated", "Very angry"])
]What goes over the wire
TypeSafeAPI.prepare/1 validates the question set and serializes it once. The encoded
questions keep the order you wrote them in, and a batch splices the same bytes into every
request instead of encoding the questions again per state.
{:ok, prepared} = TypeSafeAPI.prepare(questions)
prepared
body = %{"state" => state, "model" => client.model, "questions" => prepared.encoded}
req = TypeSafeAPI.HTTP.build(client, :post, TypeSafeAPI.SystemOne.path(), body)
IO.puts("POST #{client.base_url}#{TypeSafeAPI.SystemOne.path()}")
for {k, v} <- req.headers, k != "authorization", do: IO.puts("#{k}: #{Enum.join(List.wrap(v), ", ")}")
IO.puts("authorization: Bearer sk-***\n")
IO.puts(JSON.encode!(body))Raw response
The raw HTTP layer returns maps, plus status, headers, request id, and retry count.
{:ok, resp} = TypeSafeAPI.HTTP.request(client, :post, TypeSafeAPI.SystemOne.path(), body)
respTyped result
evaluate/3 does all of the above and decodes into typed answer structs.
{:ok, result} = TypeSafeAPI.evaluate(client, state, questions)
result.answersresult.usageRouting on the answers
alias TypeSafeAPI.Answer
cond do
Answer.yes?(result.answers.urgent) and result.answers.anger.level >= 1 ->
{:escalate, result.answers.dept.choice}
true ->
{:queue, result.answers.dept.choice}
endModels
{:ok, models} = TypeSafeAPI.models(client)
models