|
defmodule MedicalTranscriptionWeb.HomeLive.Index do |
|
use MedicalTranscriptionWeb, :live_view |
|
|
|
@impl Phoenix.LiveView |
|
def mount(_params, _session, socket) do |
|
|
|
|
|
initial_state = %{ |
|
current_recording_id: 0, |
|
uploaded_file_name: nil, |
|
status: :pending, |
|
summary_keywords: [] |
|
} |
|
|
|
socket = |
|
socket |
|
|> assign(initial_state) |
|
|> stream(:transcription_rows, []) |
|
|> allow_upload(:audio, accept: ~w(.mp3), max_entries: 1) |
|
|
|
{:ok, socket} |
|
end |
|
|
|
@impl Phoenix.LiveView |
|
def render(assigns) do |
|
~H""" |
|
<div class="flex-1 flex flex-col space-y-6"> |
|
<.result_heading |
|
status={@status} |
|
filename={@uploaded_file_name} |
|
summary_keywords={@summary_keywords} |
|
/> |
|
|
|
<%= if @status != :pending do %> |
|
<.result_list rows={@streams.transcription_rows} /> |
|
<% end %> |
|
|
|
<%= if @status == :pending do %> |
|
<div class="flex-1 flex flex-col justify-center items-center gap-4"> |
|
<img src={~p"/images/logo.svg"} width="106" /> |
|
<p class="text-2xl leading-normal font-semibold">Medical Code Transcriber</p> |
|
</div> |
|
<.upload_form audio_upload={@uploads.audio} /> |
|
<% end %> |
|
</div> |
|
""" |
|
end |
|
|
|
@impl true |
|
def handle_event("validate", _params, socket) do |
|
{:noreply, socket} |
|
end |
|
|
|
@impl true |
|
def handle_event("save", _params, socket) do |
|
filename = |
|
socket.assigns.uploads.audio.entries |
|
|> Enum.at(0) |
|
|> Map.get(:client_name) |
|
|
|
uploaded_files = |
|
consume_uploaded_entries(socket, :audio, fn %{path: path}, _entry -> |
|
dest = Path.join(System.tmp_dir(), Path.basename(path)) |
|
File.cp!(path, dest) |
|
{:ok, dest} |
|
end) |
|
|
|
uploaded_file = Enum.at(uploaded_files, 0) |
|
live_view_pid = self() |
|
|
|
Task.async(fn -> transcribe_and_tag_audio(live_view_pid, uploaded_file) end) |
|
|
|
socket = |
|
socket |
|
|> assign(:status, :loading) |
|
|> assign(:summary_keywords, []) |
|
|> assign(:transcription_rows, []) |
|
|> assign(:uploaded_file_name, filename) |
|
|
|
{:noreply, socket} |
|
end |
|
|
|
@impl true |
|
def handle_event("add_feedback", params, socket) do |
|
text_vector = MedicalTranscription.Coding.compute_vector_as_list(params["text"]) |
|
|
|
result = |
|
params |
|
|> Map.put("text_vector", text_vector) |
|
|> MedicalTranscription.Feedback.track_response() |
|
|
|
socket = |
|
case result do |
|
{:ok, message} -> put_flash(socket, :info, message) |
|
{:error, messages} -> put_flash(socket, :error, messages) |
|
end |
|
|
|
{:noreply, socket} |
|
end |
|
|
|
@impl true |
|
def handle_event("reset_to_pending", _params, socket) do |
|
{:noreply, assign(socket, :status, :pending)} |
|
end |
|
|
|
@impl true |
|
def handle_event("toggle_recording", _params, socket) do |
|
recording = GenServer.call(RecordingPipeline, :toggle_recording) |
|
|
|
new_status = |
|
if recording do |
|
:streaming_audio |
|
else |
|
:success |
|
end |
|
|
|
{:noreply, assign(socket, :status, new_status)} |
|
end |
|
|
|
@impl true |
|
def handle_info({:transcription_row, chunk_result}, socket) do |
|
|
|
|
|
|
|
{:noreply, stream_insert(socket, :transcription_rows, chunk_result)} |
|
end |
|
|
|
@impl true |
|
def handle_info({:new_keywords, new_keywords}, socket) do |
|
socket = |
|
update(socket, :summary_keywords, fn keywords -> keywords ++ [new_keywords] end) |
|
|
|
{:noreply, socket} |
|
end |
|
|
|
@impl true |
|
def handle_info({:received_audio_payload, transcribed_text}, socket) do |
|
tags = MedicalTranscription.Coding.process_chunk(transcribed_text) |
|
|
|
result = %{ |
|
id: socket.assigns.current_recording_id + 1, |
|
start_mark: nil, |
|
end_mark: nil, |
|
text: transcribed_text, |
|
tags: tags |
|
} |
|
|
|
socket = |
|
socket |
|
|> assign(:status, :streaming_audio) |
|
|> stream_insert(:transcription_rows, result) |
|
|> assign(:current_recording_id, result.id) |
|
|
|
{:noreply, socket} |
|
end |
|
|
|
@impl true |
|
def handle_info({ref, _result}, socket) do |
|
|
|
|
|
Process.demonitor(ref, [:flush]) |
|
|
|
{:noreply, assign(socket, :status, :success)} |
|
end |
|
|
|
defp transcribe_and_tag_audio(live_view_pid, audio_file_path) do |
|
MedicalTranscription.Transcription.stream_transcription_and_search( |
|
live_view_pid, |
|
audio_file_path |
|
) |
|
end |
|
|
|
def error_to_string(:too_large), do: "Too large" |
|
def error_to_string(:not_accepted), do: "You have selected an unacceptable file type" |
|
end |
|
|