defmodule IbmWatsonAssistant do @moduledoc """ Module responsible for assistant messages ## Config ```elixir # config.exs config :ibm_watson_assistant, api_key: "123456-awesome-api-key", id: "123456-awesome-assistant-id", url: "123456-awesome-url", version: "YYYY-MM-DD" ``` ## Start ```elixir # application.ex children = [ IbmWatsonAssistant ] ``` """ use GenServer alias IbmWatsonAssistant.IamAuth def start_link(_) do IamAuth.start_link([]) id = Application.fetch_env!(:ibm_watson_assistant, :id) url = Application.fetch_env!(:ibm_watson_assistant, :url) version = Application.fetch_env!(:ibm_watson_assistant, :version) access_token = IamAuth.get_token() middleware = [ {Tesla.Middleware.BaseUrl, "#{url}/v2/assistants/#{id}"}, Tesla.Middleware.JSON, {Tesla.Middleware.BearerAuth, token: access_token} ] client_http = Tesla.client(middleware) GenServer.start_link( __MODULE__, [ client_http: client_http, version: version ], name: __MODULE__ ) end @doc """ Module to send message for assistant # Example ```elixir iex> {text, context} = IbmWatsonAssistant.message_stateless "Hi" {"Hi, how are you?", %{ "global" => %{ "session_id" => "1fd59cdd-9658-44c3-b0ff-d2ab144ef64f", "system" => %{ "session_start_time" => "2023-03-21T18:49:41.635Z", "state" => "eyJza2lsbHMiOlt7InNraWxsX3JlZmVyZW5jZSI6InNlYXJjaCBza2lsbCIsImxhbmd1YWdlIjoieHgiLCJza2lsbF90eXBlIjoic2VhcmNoIiwid29ya2VyX2RlZmluaXRpb25faWQiOiIyOWE0NzZiMi00OTNkLTRlOTQtOGEwOC1mZjY4MWUxNGQ2MjkiLCJza2lsbF9zbmFwc2hvdF9pZCI6bnVsbCwic2tpbGxfc25hcHNob3RfbmFtZSI6bnVsbCwiZGlzYWJsZWQiOnRydWUsImNvbmZpZyI6eyJiYXNpY19hdXRoZW50aWNhdGlvbiI6bnVsbCwiYmVhcmVyX2F1dGhlbnRpY2F0aW9uIjpudWxsLCJwYWdpbmF0aW9uX2VuYWJsZWQiOmZhbHNlLCJ2ZXJzaW9uIjoiMjAxOC0xMi0wMyJ9fSx7InNraWxsX3R5cGUiOiJhY3Rpb24iLCJ3b3JrZXJfZGVmaW5pdGlvbl9pZCI6IjFkMjIxOWI4LWY4M2MtNDI5MS05NTk0LTI3ZjU0MzM0YzljYyIsInNraWxsX3JlZmVyZW5jZSI6ImFjdGlvbnMgc2tpbGwiLCJsYW5ndWFnZSI6InB0LWJyIiwiY29uZmlnIjp7IndvcmtzcGFjZV9pZCI6IjFkMjIxOWI4LWY4M2MtNDI5MS05NTk0LTI3ZjU0MzM0YzljYyIsInNvdXJjZV9hc3Npc3RhbnQiOiIzMDdkOTVkOS0xZGVmLTQyMGQtYjI0Ni0yZGQ2NGFmOGMzYmYiLCJza2lsbF9yZWZlcmVuY2VfaWQiOm51bGx9LCJkaXNhYmxlZCI6ZmFsc2UsInNraWxsX3NuYXBzaG90X2lkIjpudWxsLCJza2lsbF9zbmFwc2hvdF9uYW1lIjpudWxsfSx7InNraWxsX3R5cGUiOiJkaWFsb2ciLCJ3b3JrZXJfZGVmaW5pdGlvbl9pZCI6IjhlZGNlNGY3LTE5ZGYtNDVlOS04Yzk0LWJiYzY3MWEwMmYwNyIsInNraWxsX3JlZmVyZW5jZSI6Im1haW4gc2tpbGwiLCJsYW5ndWFnZSI6InB0LWJyIiwiY29uZmlnIjp7IndvcmtzcGFjZV9pZCI6IjhlZGNlNGY3LTE5ZGYtNDVlOS04Yzk0LWJiYzY3MWEwMmYwNyIsInNvdXJjZV9hc3Npc3RhbnQiOiIzMDdkOTVkOS0xZGVmLTQyMGQtYjI0Ni0yZGQ2NGFmOGMzYmYiLCJza2lsbF9yZWZlcmVuY2VfaWQiOm51bGx9LCJkaXNhYmxlZCI6dHJ1ZSwic2tpbGxfc25hcHNob3RfaWQiOm51bGwsInNraWxsX3NuYXBzaG90X25hbWUiOm51bGx9XSwiYWdlbnRfZGVmaW5pdGlvbl9pZCI6IjU1YzkzOWE0LTA0M2QtNDBiYy1iNDk3LTkxY2ZjZjE2MmFkZCIsInRlbmFudF9pZCI6Ijg1NWVjMmNlLTgxNzItNGUwZi04OWZiLThhOGZiZDMwODVhNSIsImRlZmF1bHRfaW5zdGFuY2UiOnRydWUsImRpc2FibGVfZmFsbGJhY2siOnRydWV9", "turn_count" => 1, "user_id" => "1fd59cdd-9658-44c3-b0ff-d2ab144ef64f" } }, "skills" => %{ "actions skill" => %{ "action_variables" => %{}, "skill_variables" => %{"action" => "show_menu"}, "system" => %{ "state" => "eyJzZXNzaW9uX3N0YXJ0X3RpbWUiOiIyMDIzLTAzLTIxVDE4OjQ5OjQxLjYzNVoiLCJzZXNzaW9uX2lkIjoiMWZkNTljZGQtOTY1OC00NGMzLWIwZmYtZDJhYjE0NGVmNjRmIiwic2tpbGxfcmVmZXJlbmNlIjoiYWN0aW9ucyBza2lsbCIsImFzc2lzdGFudF9pZCI6IjU1YzkzOWE0LTA0M2QtNDBiYy1iNDk3LTkxY2ZjZjE2MmFkZCIsImRpZ3Jlc3NlZF9mcm9tIjpudWxsLCJzaGFkb3dfdmFyaWFibGVzIjp7fSwibm9fYWN0aW9uX21hdGNoZXNfY291bnQiOjEsIl9ub2RlX291dHB1dF9tYXAiOnsiYW55dGhpbmdfZWxzZSBzdGVwXzAwMSI6eyIwIjpbMF19fSwiYWN0aW9uX3N0YWNrIjpbXSwic3RyaWtlX2NvdW50IjoxfQ==" } } } }} ``` """ def message_stateless(text, context \\ %{}) do GenServer.call(__MODULE__, {:message_stateless, text, context}) end @impl true def init(state), do: {:ok, state} @impl true def handle_call({:message_stateless, text, context}, _from, state) do with {:ok, client_http} <- Keyword.fetch(state, :client_http), {:ok, version} <- Keyword.fetch(state, :version) do %Tesla.Env{ body: %{ "output" => %{ "generic" => generic }, "context" => context } } = Tesla.post!(client_http, "/message?version=#{version}", %{ input: %{text: text}, context: context }) {:reply, { generic |> Enum.at(0) |> Map.fetch!("text"), context }, state} end end end