131 lines
3.7 KiB
Elixir
131 lines
3.7 KiB
Elixir
defmodule MicrosoftTranslator.Client do
|
|
@attempt_delay 3_000
|
|
@base_host "api.cognitive.microsofttranslator.com"
|
|
@base_path "/"
|
|
@api_methods %{
|
|
languages: %{
|
|
method: :get,
|
|
path: "languages"
|
|
},
|
|
detect: %{
|
|
method: :post,
|
|
path: "detect"
|
|
},
|
|
translate: %{
|
|
method: :post,
|
|
path: "translate"
|
|
}
|
|
}
|
|
@api_default_params %{
|
|
"api-version" => "3.0"
|
|
}
|
|
@availaible_api_methods Map.keys(@api_methods)
|
|
@default_headers [{"Content-Type", "application/json"}]
|
|
|
|
alias MicrosoftTranslator.Auth
|
|
|
|
def call(api_method \\ :languages, args \\ %{})
|
|
when api_method in @availaible_api_methods and is_map(args) do
|
|
body = generate_body(api_method, args)
|
|
headers = generate_headers()
|
|
params = generate_params(api_method, args)
|
|
|
|
api_method
|
|
|> fetch(headers, body, params)
|
|
|> parse(api_method)
|
|
end
|
|
|
|
defp generate_headers(headers \\ [])
|
|
|
|
defp generate_headers(header) when is_tuple(header),
|
|
do: generate_headers([header])
|
|
|
|
defp generate_headers(headers) when is_list(headers),
|
|
do: @default_headers ++ Auth.authorization_headers() ++ headers
|
|
|
|
defp generate_params(:translate, params) do
|
|
params
|
|
|> Map.take([:to, :from])
|
|
|> params_to_string()
|
|
end
|
|
|
|
defp generate_params(api_method, _params) when api_method in [:detect, :languages],
|
|
do: params_to_string(%{})
|
|
|
|
defp params_to_string(params_map) do
|
|
params_map
|
|
|> Map.merge(@api_default_params)
|
|
|> Enum.reduce("", fn {key, value}, acc -> acc <> "&" <> "#{key}" <> "=" <> "#{value}" end)
|
|
|> String.replace_leading("&", "?")
|
|
end
|
|
|
|
defp generate_body(method, params), do: transform_body(method, params) |> Jason.encode!()
|
|
|
|
defp transform_body(:languages, _), do: %{}
|
|
|
|
defp transform_body(method, params) when method in [:detect, :translate],
|
|
do: [%{text: Map.fetch!(params, :text)}]
|
|
|
|
defp transform_body(_, params), do: params
|
|
|
|
defp parse(%{body: body}, api_method) do
|
|
Jason.decode!(body, keys: :atoms)
|
|
|> process_response(api_method)
|
|
end
|
|
|
|
defp parse(%Mojito.Error{reason: :timeout}, api_method) do
|
|
%{error: %{code: :timeout, message: "timeout"}}
|
|
|> process_response(api_method)
|
|
end
|
|
|
|
defp process_response(response, api_method) do
|
|
case response do
|
|
%{error: %{code: code, message: message}} ->
|
|
%{error: %{code: code, message: message}}
|
|
|
|
list when is_list(list) and api_method in ~w(detect translate)a ->
|
|
list
|
|
|> List.first()
|
|
|> transform_response(api_method)
|
|
|
|
map when is_map(map) and api_method in ~w(languages)a ->
|
|
transform_response(map, api_method)
|
|
end
|
|
end
|
|
|
|
defp transform_response(response, :detect) when is_map(response) do
|
|
case Map.fetch(response, :language) do
|
|
{:ok, language} -> %{languageCode: language}
|
|
end
|
|
end
|
|
|
|
defp transform_response(response, :translate) when is_map(response),
|
|
do: Map.take(response, ~w(translations)a)
|
|
|
|
defp transform_response(%{dictionary: dictionary}, :languages) do
|
|
dictionary
|
|
|> Enum.map(fn {key, %{name: name, nativeName: native, dir: dir}} ->
|
|
%{code: "#{key}", name: name, nativeName: native, dir: dir}
|
|
end)
|
|
end
|
|
|
|
def fetch(api_method, headers, body, params, attempt \\ 0) do
|
|
method = @api_methods[api_method].method
|
|
url = "https://#{@base_host}#{@base_path}#{@api_methods[api_method].path}#{params}"
|
|
|
|
case Mojito.request(method, url, headers, body) do
|
|
{:ok, response} ->
|
|
response
|
|
|
|
{:error, %Mojito.Error{reason: :timeout} = response} ->
|
|
if attempt < 2 do
|
|
:timer.sleep(@attempt_delay)
|
|
IO.inspect(url, label: "Attempt #{attempt + 1}")
|
|
fetch(api_method, headers, body, params, attempt + 1)
|
|
else
|
|
response
|
|
end
|
|
end
|
|
end
|
|
end
|