Update Deepl translation
Now getting auth-key from db.
This commit is contained in:
@ -6,99 +6,93 @@ defmodule Outlook.Translators do
|
||||
import Ecto.Query, warn: false
|
||||
alias Outlook.Repo
|
||||
|
||||
alias Outlook.Translators.DeeplAccount
|
||||
alias Outlook.InternalTree.TranslationUnit
|
||||
alias Outlook.Translators.{DeeplAccount,Deepl}
|
||||
alias OutlookWeb.HtmlDocComponent
|
||||
|
||||
@doc """
|
||||
Returns the list of deepl_accounts.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> list_deepl_accounts()
|
||||
[%DeeplAccount{}, ...]
|
||||
|
||||
"""
|
||||
def list_deepl_accounts do
|
||||
Repo.all(DeeplAccount)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets a single deepl_account.
|
||||
|
||||
Raises `Ecto.NoResultsError` if the Deepl account does not exist.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> get_deepl_account!(123)
|
||||
%DeeplAccount{}
|
||||
|
||||
iex> get_deepl_account!(456)
|
||||
** (Ecto.NoResultsError)
|
||||
|
||||
"""
|
||||
def get_deepl_account!(id), do: Repo.get!(DeeplAccount, id)
|
||||
|
||||
@doc """
|
||||
Creates a deepl_account.
|
||||
def get_deepl_auth_key(user_id) do
|
||||
query =
|
||||
from DeeplAccount,
|
||||
where: [user_id: ^user_id],
|
||||
select: [:auth_key]
|
||||
Repo.one!(query)
|
||||
|> Map.get(:auth_key)
|
||||
end
|
||||
|
||||
## Examples
|
||||
|
||||
iex> create_deepl_account(%{field: value})
|
||||
{:ok, %DeeplAccount{}}
|
||||
|
||||
iex> create_deepl_account(%{field: bad_value})
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def create_deepl_account(attrs \\ %{}) do
|
||||
%DeeplAccount{}
|
||||
|> DeeplAccount.changeset(attrs)
|
||||
|> Repo.insert()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Updates a deepl_account.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> update_deepl_account(deepl_account, %{field: new_value})
|
||||
{:ok, %DeeplAccount{}}
|
||||
|
||||
iex> update_deepl_account(deepl_account, %{field: bad_value})
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def update_deepl_account(%DeeplAccount{} = deepl_account, attrs) do
|
||||
deepl_account
|
||||
|> DeeplAccount.changeset(attrs)
|
||||
|> Repo.update()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Deletes a deepl_account.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> delete_deepl_account(deepl_account)
|
||||
{:ok, %DeeplAccount{}}
|
||||
|
||||
iex> delete_deepl_account(deepl_account)
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def delete_deepl_account(%DeeplAccount{} = deepl_account) do
|
||||
Repo.delete(deepl_account)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns an `%Ecto.Changeset{}` for tracking deepl_account changes.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> change_deepl_account(deepl_account)
|
||||
%Ecto.Changeset{data: %DeeplAccount{}}
|
||||
|
||||
"""
|
||||
def change_deepl_account(%DeeplAccount{} = deepl_account, attrs \\ %{}) do
|
||||
DeeplAccount.changeset(deepl_account, attrs)
|
||||
end
|
||||
|
||||
|
||||
def translate(translation, current_user) do
|
||||
%{lang: target_lang,
|
||||
article: %{content: article_tree, language: source_lang}
|
||||
} = translation
|
||||
article_as_html = prepare_article(article_tree)
|
||||
auth_key = get_deepl_auth_key(current_user.id)
|
||||
args = [
|
||||
self(),
|
||||
article_as_html,
|
||||
%{
|
||||
source_lang: source_lang,
|
||||
target_lang: target_lang,
|
||||
auth_key: auth_key
|
||||
}
|
||||
]
|
||||
Task.start_link(Deepl, :translate, args)
|
||||
end
|
||||
|
||||
defp prepare_article(tree) do
|
||||
# Logger.info "so far."
|
||||
HtmlDocComponent.render_doc(%{tree: tree})
|
||||
|> Phoenix.HTML.Safe.to_iodata()
|
||||
|> IO.iodata_to_binary()
|
||||
end
|
||||
|
||||
def process_translation_result(result, tunit_ids) do
|
||||
# TODO: update :our_character_count
|
||||
process_translation(result.translation, tunit_ids)
|
||||
end
|
||||
|
||||
def process_translation(translation, tunit_ids) do
|
||||
tunit_map = translation
|
||||
|> Floki.parse_fragment!
|
||||
|> Floki.find("span.tunit")
|
||||
|> Enum.map(fn {_,atts,cont} ->
|
||||
%TranslationUnit{
|
||||
uuid: Enum.find(atts, fn {k,_} -> k == "uuid" end) |> Tuple.to_list |> Enum.at(1),
|
||||
content: Floki.raw_html(cont),
|
||||
status: :untranslated
|
||||
}
|
||||
end)
|
||||
|> Enum.map(fn tunit -> {tunit.uuid, tunit} end)
|
||||
|> Enum.into(%{})
|
||||
|
||||
case Enum.sort(Map.keys(tunit_map)) == Enum.sort(tunit_ids) do
|
||||
true -> {:ok, tunit_map}
|
||||
false -> {:error, "keys don't equal the originals"}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
defmodule Outlook.Translators.Deepl do
|
||||
|
||||
def test(pid) do
|
||||
for n <- 0..100 do
|
||||
send(pid, {:progress, %{progress: n}})
|
||||
Process.sleep 50
|
||||
end
|
||||
def translate(pid, article, options) do
|
||||
send(pid, {:progress, %{progress: 0}})
|
||||
credentials = start_translation(article, options)
|
||||
status = check_status(pid, credentials)
|
||||
translation = get_translation(credentials)
|
||||
send(pid, {:translation, %{translation: translation, billed_characters: status.billed_characters}})
|
||||
Process.sleep 1000
|
||||
send(pid, {:progress, %{progress: nil}})
|
||||
end
|
||||
|
||||
@ -13,10 +15,11 @@ defmodule Outlook.Translators.Deepl do
|
||||
@doc """
|
||||
Upload the content to translate and return document_id and document_key as Map.
|
||||
"""
|
||||
def start_translation %{auth_key: auth_key} = _credentials, content, target_lang do
|
||||
def start_translation content, options do
|
||||
form = get_multipart_form(
|
||||
[
|
||||
{"target_lang", target_lang},
|
||||
{"source_lang", options.source_lang},
|
||||
{"target_lang", options.target_lang},
|
||||
{"file", content, {"form-data", [{:name, "file"}, {:filename, "datei.html"}]}, []}
|
||||
]
|
||||
)
|
||||
@ -25,16 +28,16 @@ defmodule Outlook.Translators.Deepl do
|
||||
:post,
|
||||
"https://api-free.deepl.com/v2/document",
|
||||
form,
|
||||
get_multipart_headers(auth_key)
|
||||
get_multipart_headers(options.auth_key)
|
||||
)
|
||||
Jason.decode!(response_raw.body, keys: :atoms)
|
||||
|> Map.put(:auth_key, auth_key)
|
||||
|> Map.put(:auth_key, options.auth_key)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Upload the content to translate and return the estimated time until done.
|
||||
Check the status until translation is "done".
|
||||
"""
|
||||
def check_status credentials do
|
||||
def check_status pid, credentials do
|
||||
response_raw = HTTPoison.request!(
|
||||
:post,
|
||||
"https://api-free.deepl.com/v2/document/#{credentials.document_id}",
|
||||
@ -45,8 +48,12 @@ defmodule Outlook.Translators.Deepl do
|
||||
|
||||
case response do
|
||||
%{status: "translating"} ->
|
||||
Process.sleep(String.to_integer(response.seconds_remaining) * 1000)
|
||||
check_status(credentials)
|
||||
steps = response.seconds_remaining * 5
|
||||
for n <- 0..steps do
|
||||
send(pid, {:progress, %{progress: 100 * n / steps}})
|
||||
Process.sleep 200
|
||||
end
|
||||
check_status(pid, credentials)
|
||||
%{status: "done"} ->
|
||||
response
|
||||
end
|
||||
|
||||
@ -63,9 +63,21 @@ defmodule OutlookWeb.TranslationLive.FormComponent do
|
||||
{:ok, socket |> assign(deepl_progress: progress)}
|
||||
end
|
||||
|
||||
def update(%{deepl_translation: translation}, socket) do
|
||||
tunit_keys = Map.keys(socket.assigns.translation_content)
|
||||
case Outlook.Translators.process_translation_result(translation, tunit_keys) do
|
||||
{:ok, new_translation_content} ->
|
||||
{:ok, socket
|
||||
|> assign(translation_content: new_translation_content)
|
||||
|> update_current_tunit()}
|
||||
{:error, message} ->
|
||||
{:ok, socket |> put_flash(:error, message)}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("translate-deepl", _, socket) do
|
||||
Task.start_link(Outlook.Translators.Deepl, :test, [self()])
|
||||
Outlook.Translators.translate(socket.assigns.translation, socket.assigns.current_user)
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
@ -98,11 +110,21 @@ defmodule OutlookWeb.TranslationLive.FormComponent do
|
||||
|> assign(:current_tunit, socket.assigns.translation_content[uuid])}
|
||||
end
|
||||
|
||||
@doc "updating on browser events"
|
||||
def handle_event("update_current_tunit", %{"content" => content}, socket) do
|
||||
tunit = %TranslationUnit{socket.assigns.current_tunit | content: content}
|
||||
{:noreply, socket |> assign(:current_tunit, tunit)}
|
||||
end
|
||||
|
||||
|
||||
# updating after Deepl translation
|
||||
defp update_current_tunit(socket) when is_struct(socket.assigns.current_tunit) do
|
||||
assign(socket,
|
||||
:current_tunit,
|
||||
socket.assigns.translation_content[socket.assigns.current_tunit.uuid])
|
||||
end
|
||||
defp update_current_tunit(socket), do: socket
|
||||
|
||||
defp update_translation_with_current_tunit(socket) do
|
||||
translation_content = if socket.assigns.current_tunit do
|
||||
socket.assigns.translation_content
|
||||
|
||||
@ -17,6 +17,7 @@ defmodule OutlookWeb.TranslationLive.NewEdit do
|
||||
action={@live_action}
|
||||
translation={@translation}
|
||||
translation_content={@translation_content}
|
||||
current_user={@current_user}
|
||||
navigate={~p"/translations"}
|
||||
/>
|
||||
"""
|
||||
@ -56,4 +57,9 @@ defmodule OutlookWeb.TranslationLive.NewEdit do
|
||||
send_update(self(), FormComponent, progress: payload.progress, id: @form_cmpnt_id)
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_info({:translation, payload}, socket) do
|
||||
send_update(self(), FormComponent, deepl_translation: payload, id: @form_cmpnt_id)
|
||||
{:noreply, socket}
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user