noahsettersten's picture
refactor: Move code search into TranscriptionTextComponent
3748deb
raw
history blame
7.34 kB
defmodule MedicalTranscriptionWeb.Components do
@moduledoc """
Functional UI components for the main transcription and coding view.
"""
use Phoenix.Component
alias Phoenix.LiveView.JS
alias MedicalTranscription.Utilities
import MedicalTranscriptionWeb.CoreComponents
alias MedicalTranscriptionWeb.Components.TranscriptionTextComponent
use MedicalTranscriptionWeb, :verified_routes
def upload_form(assigns) do
~H"""
<form
id="audio-form"
phx-submit="save"
phx-change="validate"
class="w-full flex flex-col items-center gap-[21px]"
>
<div class="w-full px-4 py-[19px] rounded-[10px] flex items-center bg-light-divider">
<button
type="button"
phx-click="toggle_recording"
class="mr-2 h-full px-3 py-2.5 rounded-lg border border-emerald-300 bg-emerald-200"
>
<.icon name="hero-microphone" class="w-6 h-6" />
</button>
<label
for={@audio_upload.ref}
class="cursor-pointer mr-4 px-[16.5px] py-[9.941667px] rounded-lg bg-[#444444]/10"
>
<img src={~p"/images/paperclip.svg"} width="15" height="30" />
</label>
<.live_file_input
class="flex-1 cursor-pointer file:hidden file:font-secondary file:text-sm file:rounded-full file:px-4 file:py-2 file:border-0 file:bg-brand file:hover:bg-brand-active file:text-white"
upload={@audio_upload}
/>
<button name="submit-btn" title="Upload and process file">
<img src={~p"/images/upload.svg"} />
</button>
</div>
<p class="leading-normal text-type-black-secondary">Audio file can be .mp3</p>
</form>
"""
end
def loading_message(assigns) do
~H"""
<%= if @visible do %>
<div class="flex gap-2 items-center p-2 rounded-md text-slate-800 text-sm bg-slate-200 border border-slate-300">
<.icon name="hero-arrow-path" class="w-4 h-4 animate-spin" />
<p>Transcribing and tagging audio file...</p>
</div>
<% end %>
"""
end
def result_heading(assigns) do
if Enum.member?([:loading, :streaming_audio, :success], assigns.status) do
~H"""
<div class="flex justify-between">
<div class="flex items-center">
<%= case @status do %>
<% status when status in [:loading, :streaming_audio] -> %>
<img src={~p"/images/loading.svg"} width="36" class="mr-6 animate-spin" />
<% :success -> %>
<img src={~p"/images/checkmark.svg"} width="46" class="mr-[17px]" />
<% end %>
<.record_button_in_heading status={@status} />
<div class="px-[14px] py-3 flex items-center gap-3 bg-brand rounded-lg text-white">
<img src={~p"/images/document.svg"} width="20" />
<span class="font-secondary"><%= @filename %></span>
</div>
</div>
<button phx-click="reset_to_pending" type="button" class="p-3 rounded-lg bg-[#444444]/10">
<.icon name="hero-x-circle" class="w-6 h-6" />
</button>
</div>
<div class="border-b border-[#444444]/20">
<div class="px-4 py-2 flex items-center gap-2">
<img src={~p"/images/calendar.svg"} width="16" />
<span class="text-sm leading-normal font-bold text-type-black-tertiary uppercase">
<%= Calendar.strftime(DateTime.now!("Etc/UTC"), "%a, %b %d, %Y, %I:%M %p") %>
</span>
</div>
<div class="px-4 pt-2 pb-10 flex flex-col gap-2">
<p class="leading-normal font-bold text-type-black-primary uppercase">Summary Keywords</p>
<p
class="text-sm leading-normal text-type-black-tertiary"
id="keyword_list"
class="flex flex-col gap-14"
>
<!-- coronary, artery, disease, unstable, angina, admitted -->
<%= for keyword <- format_keywords(@summary_keywords) do %>
<span class="" title={keyword.score}><%= keyword.label %>,</span>
<% end %>
</p>
</div>
</div>
"""
else
~H""
end
end
def record_button_in_heading(assigns) when assigns.status == :streaming_audio do
~H"""
<button phx-click="toggle_recording" class="mr-6 px-4 py-3 bg-red-200 rounded-lg">
<.icon name="hero-microphone" class="animate-pulse" />
</button>
"""
end
def record_button_in_heading(assigns) do
~H"""
<button phx-click="toggle_recording" class="mr-6 px-4 py-3 bg-emerald-200 rounded-lg">
<.icon name="hero-microphone" />
</button>
"""
end
def format_keywords(keyword_predictions) do
keyword_predictions
|> List.flatten()
|> Enum.sort_by(& &1.score, :desc)
|> Enum.take(7)
end
def result_list(assigns) do
~H"""
<div
id="result_list"
class="flex flex-col gap-14"
phx-update={match?(%Phoenix.LiveView.LiveStream{}, @rows) && "stream"}
>
<%= for {dom_id, row} <- @rows do %>
<.live_component
module={TranscriptionTextComponent}
id={dom_id}
start_mark={row.start_mark}
end_mark={row.end_mark}
text={row.text}
/>
<% end %>
</div>
"""
end
def tag_result(assigns) do
~H"""
<div class="flex items-center gap-4 px-[14px] py-3 text-sm">
<div class="flex gap-3">
<.feedback_button code_vector_id={@code_vector_id} text={@text} response="true" />
<.feedback_button code_vector_id={@code_vector_id} text={@text} response="false" />
</div>
<div class="w-1 h-full border-l border-[#444444]/20"></div>
<div
class={"flex flex-col gap-1 font-secondary text-type-black-primary ml-4 px-2 py-1 rounded #{code_color(@weighting)}"}
title={code_title(@score, @weighting)}
>
<p class="text-lg font-bold leading-[22.97px]"><%= @code %></p>
<p class="text-base leading-[20.42px]"><%= @label %></p>
</div>
</div>
"""
end
def code_color(weighting) do
cond do
:positive in weighting and :negative in weighting -> "bg-orange-200/40"
:positive in weighting -> "bg-emerald-200/40"
:negative in weighting -> "bg-red-200/40"
true -> ""
end
end
def code_title(score, weighting) do
weighting_description =
if length(weighting) > 0 do
weighting
|> Utilities.tally()
|> Utilities.tally_to_string()
|> String.replace_prefix("", "Weighting: ")
else
""
end
"Similarity score: #{trunc(score * 100) / 100}. #{weighting_description}"
end
defp feedback_button(assigns) do
~H"""
<button
phx-click={
JS.push("add_feedback")
|> JS.add_class("ring-2 ring-orange-500/40")
}
phx-value-code_vector_id={@code_vector_id}
phx-value-text={@text}
phx-value-response={@response}
type="button"
class="p-2 border border-button-deactivated-background rounded-lg hover:bg-slate-200"
>
<%= if @response == "true" do %>
<img src={~p"/images/thumbs-up.svg"} width="20" height="20" class="w-5 h-5 min-w-[20px]" />
<% else %>
<img src={~p"/images/thumbs-down.svg"} width="20" height="20" class="w-5 h-5 min-w-[20px]" />
<% end %>
</button>
"""
end
end