Commit
•
78111fe
1
Parent(s):
47f0c94
feat: Transcribe using FLAME on a Fly GPU
Browse files- config/runtime.exs +11 -0
- lib/medicode/application.ex +17 -4
- lib/medicode/transcription_server.ex +16 -13
- mix.exs +2 -1
- mix.lock +1 -0
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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
|
|
|
|
|
|
|
|
|
|
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"},
|