timgremore commited on
Commit
78111fe
1 Parent(s): 47f0c94

feat: Transcribe using FLAME on a Fly GPU

Browse files
config/runtime.exs CHANGED
@@ -72,6 +72,17 @@ if config_env() == :prod do
72
  ],
73
  secret_key_base: secret_key_base
74
 
 
 
 
 
 
 
 
 
 
 
 
75
  # ## SSL Support
76
  #
77
  # To get SSL working, you will need to add the `https` key
 
72
  ],
73
  secret_key_base: secret_key_base
74
 
75
+ if config_env() == :prod do
76
+ config :flame, :backend, FLAME.FlyBackend
77
+
78
+ config :flame, FLAME.FlyBackend,
79
+ token: System.fetch_env!("MEDICODE_API_TOKEN"),
80
+ gpu_kind: "a100-pcie-40gb",
81
+ cpu_kind: "performance",
82
+ cpus: 8,
83
+ memory_mb: 20_480
84
+ end
85
+
86
  # ## SSL Support
87
  #
88
  # To get SSL working, you will need to add the `https` key
lib/medicode/application.ex CHANGED
@@ -9,12 +9,15 @@ defmodule Medicode.Application do
9
  def start(_type, _args) do
10
  Logger.add_backend(Sentry.LoggerBackend)
11
 
 
 
12
  children =
13
  [
14
  {MedicodeWeb.MetricsStorage, MedicodeWeb.Telemetry.metrics()},
15
  Medicode.Repo,
16
  {DNSCluster, query: Application.get_env(:medicode, :dns_cluster_query) || :ignore},
17
  {Phoenix.PubSub, name: :medicode_pubsub},
 
18
  Medicode.ServingSupervisor,
19
  {
20
  Medicode.TranscriptionSupervisor,
@@ -30,12 +33,22 @@ defmodule Medicode.Application do
30
  },
31
  # Start the Finch HTTP client for sending emails
32
  {Finch, name: Medicode.Finch}
33
- ] ++ chromic_pdf_spec()
34
 
35
  # Start a worker by calling: Medicode.Worker.start_link(arg)
36
  # {Medicode.Worker, arg},
37
  # Start to serve requests, typically the last entry
38
- children = children ++ [MedicodeWeb.Endpoint]
 
 
 
 
 
 
 
 
 
 
39
 
40
  # See https://hexdocs.pm/elixir/Supervisor.html
41
  # for other strategies and supported options
@@ -51,8 +64,8 @@ defmodule Medicode.Application do
51
  :ok
52
  end
53
 
54
- defp chromic_pdf_spec do
55
- if Application.get_env(:medicode, :skip_chromic_pdf, false) do
56
  []
57
  else
58
  # NOTE: Security implications of using Chrome:
 
9
  def start(_type, _args) do
10
  Logger.add_backend(Sentry.LoggerBackend)
11
 
12
+ flame_parent = FLAME.Parent.get()
13
+
14
  children =
15
  [
16
  {MedicodeWeb.MetricsStorage, MedicodeWeb.Telemetry.metrics()},
17
  Medicode.Repo,
18
  {DNSCluster, query: Application.get_env(:medicode, :dns_cluster_query) || :ignore},
19
  {Phoenix.PubSub, name: :medicode_pubsub},
20
+ {FLAME.Pool, name: Medicode.OfflineServing, min: 0, max: 1},
21
  Medicode.ServingSupervisor,
22
  {
23
  Medicode.TranscriptionSupervisor,
 
33
  },
34
  # Start the Finch HTTP client for sending emails
35
  {Finch, name: Medicode.Finch}
36
+ ] ++ chromic_pdf_spec(flame_parent)
37
 
38
  # Start a worker by calling: Medicode.Worker.start_link(arg)
39
  # {Medicode.Worker, arg},
40
  # Start to serve requests, typically the last entry
41
+
42
+ # Since we don't need Endpoint running within FLAME nodes, we skip
43
+ # starting it under that condition.
44
+ children =
45
+ if flame_parent do
46
+ children
47
+ else
48
+ children ++ [MedicodeWeb.Endpoint]
49
+ end
50
+
51
+ children = Enum.filter(children, & &1)
52
 
53
  # See https://hexdocs.pm/elixir/Supervisor.html
54
  # for other strategies and supported options
 
64
  :ok
65
  end
66
 
67
+ defp chromic_pdf_spec(flame_parent) do
68
+ if flame_parent || Application.get_env(:medicode, :skip_chromic_pdf, false) do
69
  []
70
  else
71
  # NOTE: Security implications of using Chrome:
lib/medicode/transcription_server.ex CHANGED
@@ -155,20 +155,23 @@ defmodule Medicode.TranscriptionServer do
155
  # complete sentences based on punctuation. We may want to suggest codes for the entire audio as a single piece as
156
  # well
157
  defp stream_transcription_and_search(audio_file_path) do
158
- # audio transcription + semantic search
159
- Medicode.TranscriptionServing
160
- |> Nx.Serving.batched_run({:file, audio_file_path})
161
- |> Enum.each(fn chunk ->
162
- result = %{
163
- start_mark: format_timestamp(chunk.start_timestamp_seconds),
164
- end_mark: format_timestamp(chunk.end_timestamp_seconds),
165
- text: chunk.text
166
- }
167
-
168
- send(self(), {:chunk, result})
 
 
 
 
 
169
  end)
170
-
171
- send(self(), :finished)
172
  end
173
 
174
  defp format_timestamp(seconds) when is_nil(seconds), do: nil
 
155
  # complete sentences based on punctuation. We may want to suggest codes for the entire audio as a single piece as
156
  # well
157
  defp stream_transcription_and_search(audio_file_path) do
158
+ target_pid = self()
159
+
160
+ FLAME.call(Medicode.OfflineServing, fn ->
161
+ Medicode.TranscriptionServing
162
+ |> Nx.Serving.batched_run({:file, audio_file_path})
163
+ |> Enum.each(fn chunk ->
164
+ result = %{
165
+ start_mark: format_timestamp(chunk.start_timestamp_seconds),
166
+ end_mark: format_timestamp(chunk.end_timestamp_seconds),
167
+ text: chunk.text
168
+ }
169
+
170
+ send(target_pid, {:chunk, result})
171
+ end)
172
+
173
+ send(target_pid, :finished)
174
  end)
 
 
175
  end
176
 
177
  defp format_timestamp(seconds) when is_nil(seconds), do: nil
mix.exs CHANGED
@@ -78,7 +78,8 @@ defmodule Medicode.MixProject do
78
  # NOTE: `override: true` avoids an issue that likely originates
79
  # from `audio_tagger` depending on a different version of bumblebee:
80
  # https://elixirforum.com/t/getting-a-weird-error-message-in-mix-ive-not-see-before-because-your-app-depends-on-xxx-empty/54475/8
81
- {:bumblebee, "~> 0.5.3", override: true}
 
82
  ]
83
  end
84
 
 
78
  # NOTE: `override: true` avoids an issue that likely originates
79
  # from `audio_tagger` depending on a different version of bumblebee:
80
  # https://elixirforum.com/t/getting-a-weird-error-message-in-mix-ive-not-see-before-because-your-app-depends-on-xxx-empty/54475/8
81
+ {:bumblebee, "~> 0.5.3", override: true},
82
+ {:flame, "~> 0.1.12"}
83
  ]
84
  end
85
 
mix.lock CHANGED
@@ -31,6 +31,7 @@
31
  "expo": {:hex, :expo, "0.5.2", "beba786aab8e3c5431813d7a44b828e7b922bfa431d6bfbada0904535342efe2", [:mix], [], "hexpm", "8c9bfa06ca017c9cb4020fabe980bc7fdb1aaec059fd004c2ab3bff03b1c599c"},
32
  "file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"},
33
  "finch": {:hex, :finch, "0.18.0", "944ac7d34d0bd2ac8998f79f7a811b21d87d911e77a786bc5810adb75632ada4", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "69f5045b042e531e53edc2574f15e25e735b522c37e2ddb766e15b979e03aa65"},
 
34
  "floki": {:hex, :floki, "0.36.1", "712b7f2ba19a4d5a47dfe3e74d81876c95bbcbee44fe551f0af3d2a388abb3da", [:mix], [], "hexpm", "21ba57abb8204bcc70c439b423fc0dd9f0286de67dc82773a14b0200ada0995f"},
35
  "fss": {:hex, :fss, "0.1.1", "9db2344dbbb5d555ce442ac7c2f82dd975b605b50d169314a20f08ed21e08642", [:mix], [], "hexpm", "78ad5955c7919c3764065b21144913df7515d52e228c09427a004afe9c1a16b0"},
36
  "gettext": {:hex, :gettext, "0.24.0", "6f4d90ac5f3111673cbefc4ebee96fe5f37a114861ab8c7b7d5b30a1108ce6d8", [:mix], [{:expo, "~> 0.5.1", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "bdf75cdfcbe9e4622dd18e034b227d77dd17f0f133853a1c73b97b3d6c770e8b"},
 
31
  "expo": {:hex, :expo, "0.5.2", "beba786aab8e3c5431813d7a44b828e7b922bfa431d6bfbada0904535342efe2", [:mix], [], "hexpm", "8c9bfa06ca017c9cb4020fabe980bc7fdb1aaec059fd004c2ab3bff03b1c599c"},
32
  "file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"},
33
  "finch": {:hex, :finch, "0.18.0", "944ac7d34d0bd2ac8998f79f7a811b21d87d911e77a786bc5810adb75632ada4", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "69f5045b042e531e53edc2574f15e25e735b522c37e2ddb766e15b979e03aa65"},
34
+ "flame": {:hex, :flame, "0.1.12", "4d46b706d35d6eb22505d0e060fe41174052eaa38f778a4762fc74dd2c9df301", [:mix], [{:req, "~> 0.4.13", [hex: :req, repo: "hexpm", optional: false]}], "hexpm", "aa25de6614455ac01e33409c08db4560fa54dd837ad116aae16c8f7c011ccd76"},
35
  "floki": {:hex, :floki, "0.36.1", "712b7f2ba19a4d5a47dfe3e74d81876c95bbcbee44fe551f0af3d2a388abb3da", [:mix], [], "hexpm", "21ba57abb8204bcc70c439b423fc0dd9f0286de67dc82773a14b0200ada0995f"},
36
  "fss": {:hex, :fss, "0.1.1", "9db2344dbbb5d555ce442ac7c2f82dd975b605b50d169314a20f08ed21e08642", [:mix], [], "hexpm", "78ad5955c7919c3764065b21144913df7515d52e228c09427a004afe9c1a16b0"},
37
  "gettext": {:hex, :gettext, "0.24.0", "6f4d90ac5f3111673cbefc4ebee96fe5f37a114861ab8c7b7d5b30a1108ce6d8", [:mix], [{:expo, "~> 0.5.1", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "bdf75cdfcbe9e4622dd18e034b227d77dd17f0f133853a1c73b97b3d6c770e8b"},