medicode / lib /medical_transcription_web /components /transcription_text_component.ex
noahsettersten's picture
chore: Remove unused code for highlighting previous feedback responses
b20fcc2
raw
history blame
3.59 kB
defmodule MedicalTranscriptionWeb.Components.TranscriptionTextComponent do
@moduledoc """
Represents a portion of transcribed text and its codes and starts a task to determine keywords within the text.
"""
use MedicalTranscriptionWeb, :live_component
import MedicalTranscriptionWeb.Components
import MedicalTranscriptionWeb.Components.KeywordHighlighter
alias MedicalTranscription.Coding.CodeVectorMatch
alias AudioTagger.KeywordFinder
@impl Phoenix.LiveComponent
def update(assigns, socket) do
socket = assign_for_row(assigns, socket)
{:ok, socket}
end
defp assign_for_row(%{row: row}, socket) do
self_pid = self()
socket
|> assign(:row, row)
|> assign_async(:keywords, fn -> find_keywords(self_pid, row.text) end)
end
defp assign_for_row(_assigns, socket), do: socket
@impl Phoenix.LiveComponent
def render(assigns) do
~H"""
<div class="flex gap-12 pb-10 border-b border-[#444444]/20">
<div class="flex-1 flex flex-col gap-4">
<p class="text-[32px] leading-normal font-semibold">
<%= if !is_nil(@row.start_mark) && !is_nil(@row.end_mark) do %>
<%= @row.start_mark %> - <%= @row.end_mark %>
<% end %>
</p>
<p class="text-[28px] leading-normal text-type-black-tertiary">
<.async_result :let={keywords} assign={@keywords}>
<:loading><%= @row.text %></:loading>
<.highlight text={@row.text} keywords={keywords} />
</.async_result>
</p>
<div class="flex items-center gap-2 text-sm italic">
<.async_result assign={@keywords}>
<:loading>
<img src={~p"/images/loading.svg"} width="16" class="animate-spin" />
Finding keywords...
</:loading>
<:failed :let={reason}>There was an error finding keywords: <%= reason %></:failed>
</.async_result>
</div>
</div>
<div class="flex-1 flex flex-col items-stretch gap-3">
<%= for %CodeVectorMatch{id: id, code: code, description: label, cosine_similarity: score, weighting: weighting} <- @row.tags do %>
<.tag_result
code_vector_id={id}
code={code}
label={label}
score={score}
text={@row.text}
weighting={weighting}
/>
<% end %>
</div>
</div>
"""
end
defp find_keywords(_live_view_pid, ""), do: {:ok, %{keywords: []}}
defp find_keywords(live_view_pid, text) do
# First, we use token classification to determine parts of speech and then retrieve the verb and adjective+noun phrases.
%{entities: entities} =
Nx.Serving.batched_run(MedicalTranscription.TokenClassificationServing, text)
phrases = KeywordFinder.cleanup_phrases(entities)
# Then, we use one of two processes to determine which to show as keywords:
# 1. A slower process that looks to classify the text by the extracted phrases.
# serving = KeywordFinder.prepare_zero_shot_classification_serving(phrases)
# %{predictions: predictions} = Nx.Serving.run(serving, text)
# 2. A fast process finding the phrase closest in vector space to the whole text.
predictions = KeywordFinder.find_most_similar_label(text, phrases, 2)
# For now, retrieve the top three keywords that have a score of more than 0.25
keywords =
predictions
|> Enum.filter(fn keyword -> keyword.score > 0.25 end)
|> Enum.take(3)
send(live_view_pid, {:new_keywords, predictions})
{:ok, %{keywords: keywords}}
end
end