timgremore commited on
Commit
843f654
1 Parent(s): f94adc3

feat: Replace callback payloads with chunks

Browse files
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 `transcription_rows` stream with:
10
 
11
- |> stream(:transcription_rows, MedicalTranscriptionWeb.HomeLive.Index.SampleResults.get_sample_results())
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(:transcription_rows, dom_id: &"transcription-row-#{&1.id}")
34
- |> stream(:transcription_rows, [])
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, row} <- @streams.transcription_rows}
58
  module={TranscriptionTextComponent}
59
  id={dom_id}
60
- start_mark={row.start_mark}
61
- end_mark={row.end_mark}
62
- text={row.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, chunk_result}, socket) do
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(:transcription_rows, result)
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), do: Transcriptions.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
- assert_redirected view, ~p"/transcriptions/#{transcription.id}"
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