Commit
•
843f654
1
Parent(s):
f94adc3
feat: Replace callback payloads with chunks
Browse files- lib/medical_transcription/transcriptions/transcription_chunk.ex +4 -2
- lib/medical_transcription_web/components/transcription_text_component.ex +1 -1
- lib/medical_transcription_web/live/home_live/sample_results.ex +2 -2
- lib/medical_transcription_web/live/transcriptions_live/show.ex +18 -12
- test/medical_transcription_web/live/transcriptions_live_show_test.exs +7 -3
- test/support/fixtures/transcription_chunks_fixtures.ex +32 -0
lib/medical_transcription/transcriptions/transcription_chunk.ex
CHANGED
@@ -6,6 +6,8 @@ defmodule MedicalTranscription.Transcriptions.TranscriptionChunk do
|
|
6 |
@foreign_key_type :binary_id
|
7 |
schema "transcription_chunks" do
|
8 |
field :text, :string
|
|
|
|
|
9 |
|
10 |
belongs_to :transcription, MedicalTranscription.Transcriptions.Transcription
|
11 |
|
@@ -15,7 +17,7 @@ defmodule MedicalTranscription.Transcriptions.TranscriptionChunk do
|
|
15 |
@doc false
|
16 |
def changeset(transcription_chunk, attrs) do
|
17 |
transcription_chunk
|
18 |
-
|> cast(attrs, [:transcription_id, :text])
|
19 |
-
|> validate_required([:transcription_id, :text])
|
20 |
end
|
21 |
end
|
|
|
6 |
@foreign_key_type :binary_id
|
7 |
schema "transcription_chunks" do
|
8 |
field :text, :string
|
9 |
+
field :start_mark, :string
|
10 |
+
field :end_mark, :string
|
11 |
|
12 |
belongs_to :transcription, MedicalTranscription.Transcriptions.Transcription
|
13 |
|
|
|
17 |
@doc false
|
18 |
def changeset(transcription_chunk, attrs) do
|
19 |
transcription_chunk
|
20 |
+
|> cast(attrs, [:transcription_id, :text, :start_mark, :end_mark])
|
21 |
+
|> validate_required([:transcription_id, :text, :start_mark, :end_mark])
|
22 |
end
|
23 |
end
|
lib/medical_transcription_web/components/transcription_text_component.ex
CHANGED
@@ -40,7 +40,7 @@ defmodule MedicalTranscriptionWeb.Components.TranscriptionTextComponent do
|
|
40 |
def render(assigns) do
|
41 |
# TODO: Adjust the blue border when editing
|
42 |
~H"""
|
43 |
-
<div class="flex gap-12 pb-10 border-b border-[#444444]/20">
|
44 |
<div class="flex-1 flex flex-col gap-4">
|
45 |
<p class="px-2 text-[32px] leading-normal font-semibold">
|
46 |
<%= if !is_nil(@start_mark) && !is_nil(@end_mark) do %>
|
|
|
40 |
def render(assigns) do
|
41 |
# TODO: Adjust the blue border when editing
|
42 |
~H"""
|
43 |
+
<div id={@id} class="flex gap-12 pb-10 border-b border-[#444444]/20">
|
44 |
<div class="flex-1 flex flex-col gap-4">
|
45 |
<p class="px-2 text-[32px] leading-normal font-semibold">
|
46 |
<%= if !is_nil(@start_mark) && !is_nil(@end_mark) do %>
|
lib/medical_transcription_web/live/home_live/sample_results.ex
CHANGED
@@ -6,9 +6,9 @@ defmodule MedicalTranscriptionWeb.HomeLive.Index.SampleResults do
|
|
6 |
|
7 |
status: :success
|
8 |
|
9 |
-
And the `
|
10 |
|
11 |
-
|> stream(:
|
12 |
"""
|
13 |
|
14 |
alias AudioTagger.Structs.TagResult
|
|
|
6 |
|
7 |
status: :success
|
8 |
|
9 |
+
And the `chunks` stream with:
|
10 |
|
11 |
+
|> stream(:chunks, MedicalTranscriptionWeb.HomeLive.Index.SampleResults.get_sample_results())
|
12 |
"""
|
13 |
|
14 |
alias AudioTagger.Structs.TagResult
|
lib/medical_transcription_web/live/transcriptions_live/show.ex
CHANGED
@@ -2,7 +2,10 @@ defmodule MedicalTranscriptionWeb.TranscriptionsLive.Show do
|
|
2 |
use MedicalTranscriptionWeb, :live_view
|
3 |
|
4 |
alias MedicalTranscription.Audio.RecordingPipeline
|
|
|
5 |
alias MedicalTranscription.Transcriptions
|
|
|
|
|
6 |
alias MedicalTranscriptionWeb.Components.TranscriptionTextComponent
|
7 |
|
8 |
@impl Phoenix.LiveView
|
@@ -30,8 +33,8 @@ defmodule MedicalTranscriptionWeb.TranscriptionsLive.Show do
|
|
30 |
socket =
|
31 |
socket
|
32 |
|> assign(initial_state)
|
33 |
-
|> stream_configure(:
|
34 |
-
|> stream(:
|
35 |
|
36 |
{:ok, socket}
|
37 |
end
|
@@ -54,12 +57,12 @@ defmodule MedicalTranscriptionWeb.TranscriptionsLive.Show do
|
|
54 |
|
55 |
<div id="result_list" class="flex flex flex-col gap-14" phx-update="stream">
|
56 |
<.live_component
|
57 |
-
:for={{dom_id,
|
58 |
module={TranscriptionTextComponent}
|
59 |
id={dom_id}
|
60 |
-
start_mark={
|
61 |
-
end_mark={
|
62 |
-
text={
|
63 |
finalized_codes={@finalized_codes}
|
64 |
/>
|
65 |
</div>
|
@@ -87,7 +90,6 @@ defmodule MedicalTranscriptionWeb.TranscriptionsLive.Show do
|
|
87 |
{:noreply, socket}
|
88 |
end
|
89 |
|
90 |
-
@impl true
|
91 |
def handle_event("reset_to_pending", _params, socket) do
|
92 |
{:noreply, assign(socket, :status, :pending)}
|
93 |
end
|
@@ -112,11 +114,10 @@ defmodule MedicalTranscriptionWeb.TranscriptionsLive.Show do
|
|
112 |
end
|
113 |
|
114 |
@impl true
|
115 |
-
def handle_info({:transcription_updated,
|
116 |
# The processing sends a message as each chunk of text is coded. See here for some background and potential
|
117 |
# inspiration for this: https://elixirforum.com/t/liveview-asynchronous-task-patterns/44695
|
118 |
-
|
119 |
-
{:noreply, stream_insert(socket, :transcription_rows, chunk_result)}
|
120 |
end
|
121 |
|
122 |
def handle_info({:transcription_started, _transcription}, socket) do
|
@@ -148,7 +149,7 @@ defmodule MedicalTranscriptionWeb.TranscriptionsLive.Show do
|
|
148 |
socket =
|
149 |
socket
|
150 |
|> assign(:status, :streaming_audio)
|
151 |
-
|> stream_insert(:
|
152 |
|> assign(:current_recording_id, result.id)
|
153 |
|
154 |
{:noreply, socket}
|
@@ -179,6 +180,11 @@ defmodule MedicalTranscriptionWeb.TranscriptionsLive.Show do
|
|
179 |
{:noreply, assign(socket, :status, :success)}
|
180 |
end
|
181 |
|
182 |
-
defp get_transcription(id)
|
|
|
|
|
|
|
|
|
|
|
183 |
defp list_transcriptions(user), do: Transcriptions.list_transcriptions(user)
|
184 |
end
|
|
|
2 |
use MedicalTranscriptionWeb, :live_view
|
3 |
|
4 |
alias MedicalTranscription.Audio.RecordingPipeline
|
5 |
+
alias MedicalTranscription.Repo
|
6 |
alias MedicalTranscription.Transcriptions
|
7 |
+
alias MedicalTranscription.Transcriptions.TranscriptionChunk
|
8 |
+
|
9 |
alias MedicalTranscriptionWeb.Components.TranscriptionTextComponent
|
10 |
|
11 |
@impl Phoenix.LiveView
|
|
|
33 |
socket =
|
34 |
socket
|
35 |
|> assign(initial_state)
|
36 |
+
|> stream_configure(:chunks, dom_id: &"transcription-chunk-#{&1.id}")
|
37 |
+
|> stream(:chunks, transcription.chunks)
|
38 |
|
39 |
{:ok, socket}
|
40 |
end
|
|
|
57 |
|
58 |
<div id="result_list" class="flex flex flex-col gap-14" phx-update="stream">
|
59 |
<.live_component
|
60 |
+
:for={{dom_id, chunk} <- @streams.chunks}
|
61 |
module={TranscriptionTextComponent}
|
62 |
id={dom_id}
|
63 |
+
start_mark={chunk.start_mark}
|
64 |
+
end_mark={chunk.end_mark}
|
65 |
+
text={chunk.text}
|
66 |
finalized_codes={@finalized_codes}
|
67 |
/>
|
68 |
</div>
|
|
|
90 |
{:noreply, socket}
|
91 |
end
|
92 |
|
|
|
93 |
def handle_event("reset_to_pending", _params, socket) do
|
94 |
{:noreply, assign(socket, :status, :pending)}
|
95 |
end
|
|
|
114 |
end
|
115 |
|
116 |
@impl true
|
117 |
+
def handle_info({:transcription_updated, chunk}, socket) do
|
118 |
# The processing sends a message as each chunk of text is coded. See here for some background and potential
|
119 |
# inspiration for this: https://elixirforum.com/t/liveview-asynchronous-task-patterns/44695
|
120 |
+
{:noreply, stream_insert(socket, :chunks, chunk)}
|
|
|
121 |
end
|
122 |
|
123 |
def handle_info({:transcription_started, _transcription}, socket) do
|
|
|
149 |
socket =
|
150 |
socket
|
151 |
|> assign(:status, :streaming_audio)
|
152 |
+
|> stream_insert(:chunks, result)
|
153 |
|> assign(:current_recording_id, result.id)
|
154 |
|
155 |
{:noreply, socket}
|
|
|
180 |
{:noreply, assign(socket, :status, :success)}
|
181 |
end
|
182 |
|
183 |
+
defp get_transcription(id) do
|
184 |
+
id
|
185 |
+
|> Transcriptions.get_transcription()
|
186 |
+
|> Repo.preload(:chunks)
|
187 |
+
end
|
188 |
+
|
189 |
defp list_transcriptions(user), do: Transcriptions.list_transcriptions(user)
|
190 |
end
|
test/medical_transcription_web/live/transcriptions_live_show_test.exs
CHANGED
@@ -2,12 +2,16 @@ defmodule MedicalTranscriptionWeb.TranscriptionsLive.ShowTest do
|
|
2 |
use MedicalTranscriptionWeb.ConnCase, async: true
|
3 |
|
4 |
import Phoenix.LiveViewTest
|
5 |
-
import MedicalTranscription.{AccountsFixtures, TranscriptionsFixtures}
|
6 |
|
7 |
setup %{conn: conn} do
|
8 |
password = valid_user_password()
|
9 |
user = user_fixture(%{password: password})
|
10 |
transcription = transcription_fixture(%{filename: "my-audio.mp3"})
|
|
|
|
|
|
|
|
|
11 |
%{conn: log_in_user(conn, user), current_user: user, transcription: transcription}
|
12 |
end
|
13 |
|
@@ -18,8 +22,8 @@ defmodule MedicalTranscriptionWeb.TranscriptionsLive.ShowTest do
|
|
18 |
|
19 |
{:ok, view, html} = live(conn)
|
20 |
assert html =~ "my-audio.mp3"
|
21 |
-
|
22 |
-
|
23 |
end
|
24 |
|
25 |
test "renders 'Not Found' for 404", %{conn: conn} do
|
|
|
2 |
use MedicalTranscriptionWeb.ConnCase, async: true
|
3 |
|
4 |
import Phoenix.LiveViewTest
|
5 |
+
import MedicalTranscription.{AccountsFixtures, TranscriptionsFixtures, TranscriptionChunksFixtures}
|
6 |
|
7 |
setup %{conn: conn} do
|
8 |
password = valid_user_password()
|
9 |
user = user_fixture(%{password: password})
|
10 |
transcription = transcription_fixture(%{filename: "my-audio.mp3"})
|
11 |
+
|
12 |
+
transcription_chunk_fixture(%{transcription_id: transcription.id, text: "Foo"})
|
13 |
+
transcription_chunk_fixture(%{transcription_id: transcription.id, text: "Bar"})
|
14 |
+
|
15 |
%{conn: log_in_user(conn, user), current_user: user, transcription: transcription}
|
16 |
end
|
17 |
|
|
|
22 |
|
23 |
{:ok, view, html} = live(conn)
|
24 |
assert html =~ "my-audio.mp3"
|
25 |
+
assert html =~ "Foo"
|
26 |
+
assert html =~ "Bar"
|
27 |
end
|
28 |
|
29 |
test "renders 'Not Found' for 404", %{conn: conn} do
|
test/support/fixtures/transcription_chunks_fixtures.ex
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
defmodule MedicalTranscription.TranscriptionChunksFixtures do
|
2 |
+
@moduledoc """
|
3 |
+
This module defines test helpers for creating %TranscriptionChunk{}
|
4 |
+
entities via the `MedicalTranscription.Transcriptions` context.
|
5 |
+
"""
|
6 |
+
|
7 |
+
import MedicalTranscription.TranscriptionsFixtures
|
8 |
+
|
9 |
+
@doc """
|
10 |
+
Generate a transcription chunk.
|
11 |
+
"""
|
12 |
+
def transcription_chunk_fixture(attrs \\ %{}) do
|
13 |
+
transcription_id =
|
14 |
+
cond do
|
15 |
+
Map.has_key?(attrs, :transcription_id) -> attrs.transcription_id
|
16 |
+
Map.has_key?(attrs, :transcription) -> attrs.transcription
|
17 |
+
true -> transcription_fixture().id
|
18 |
+
end
|
19 |
+
|
20 |
+
{:ok, transcription_chunk} =
|
21 |
+
attrs
|
22 |
+
|> Enum.into(%{
|
23 |
+
transcription_id: transcription_id,
|
24 |
+
filename: "My transcription text",
|
25 |
+
start_mark: "00:00:00",
|
26 |
+
end_mark: "00:00:07"
|
27 |
+
})
|
28 |
+
|> MedicalTranscription.Transcriptions.create_chunk()
|
29 |
+
|
30 |
+
transcription_chunk
|
31 |
+
end
|
32 |
+
end
|