noahsettersten commited on
Commit
408b86f
1 Parent(s): 0a2902e

feat: Add sample livebooks

Browse files

Brought in from Hugging Face space at https://huggingface.co/spaces/headway/medical-code-transcriber/tree/main/public-apps

livebooks/sample_implementation.livemd ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!-- livebook:{"app_settings":{"auto_shutdown_ms":5000,"multi_session":true,"slug":"medical-code-transcriber"}} -->
2
+
3
+ # Medical Code Transcriber
4
+
5
+ ```elixir
6
+ Mix.install(
7
+ [
8
+ {:kino_bumblebee, "~> 0.4.0"},
9
+ {:exla, ">= 0.0.0"},
10
+ {:explorer, "~> 0.7.0"},
11
+ {:kino_explorer, "~> 0.1.11"}
12
+ ],
13
+ config: [nx: [default_backend: EXLA.Backend]]
14
+ )
15
+ ```
16
+
17
+ ## Transcribe Audio to Text
18
+
19
+ ### Step 1: Select your audio to transcribe
20
+
21
+ * First, upload (or record) your audio below.
22
+ * Then, run the second cell after the input to transcribe the audio to text.
23
+
24
+ ```elixir
25
+ {:ok, model_info} = Bumblebee.load_model({:hf, "openai/whisper-tiny"})
26
+ {:ok, featurizer} = Bumblebee.load_featurizer({:hf, "openai/whisper-tiny"})
27
+ {:ok, tokenizer} = Bumblebee.load_tokenizer({:hf, "openai/whisper-tiny"})
28
+ {:ok, generation_config} = Bumblebee.load_generation_config({:hf, "openai/whisper-tiny"})
29
+ generation_config = Bumblebee.configure(generation_config, max_new_tokens: 100)
30
+
31
+ serving =
32
+ Bumblebee.Audio.speech_to_text_whisper(
33
+ model_info,
34
+ featurizer,
35
+ tokenizer,
36
+ generation_config,
37
+ compile: [batch_size: 4],
38
+ chunk_num_seconds: 30,
39
+ timestamps: :segments,
40
+ stream: true,
41
+ defn_options: [compiler: EXLA]
42
+ )
43
+
44
+ audio_input = Kino.Input.audio("Audio", sampling_rate: featurizer.sampling_rate)
45
+ ```
46
+
47
+ ```elixir
48
+ chosen_audio = Kino.Input.read(audio_input)
49
+
50
+ audio =
51
+ chosen_audio.file_ref
52
+ |> Kino.Input.file_path()
53
+ |> File.read!()
54
+ |> Nx.from_binary(:f32)
55
+ |> Nx.reshape({:auto, chosen_audio.num_channels})
56
+ |> Nx.mean(axes: [1])
57
+
58
+ dataframe =
59
+ Nx.Serving.run(serving, audio)
60
+ |> Enum.reduce([], fn chunk, acc ->
61
+ [start_mark, end_mark] =
62
+ for seconds <- [chunk.start_timestamp_seconds, chunk.end_timestamp_seconds] do
63
+ seconds |> round() |> Time.from_seconds_after_midnight() |> Time.to_string()
64
+ end
65
+
66
+ [%{start_mark: start_mark, end_mark: end_mark, text: chunk.text}] ++ acc
67
+ end)
68
+ |> Enum.reverse()
69
+ |> Explorer.DataFrame.new()
70
+ ```
71
+
72
+ ```elixir
73
+ procedure_code_mapping = [
74
+ ["followup visit", "FOLLOWUP"],
75
+ ["cipher drug", "CIPHER"],
76
+ ["catheterization", "CATH"],
77
+ ["ventricularography", "VTR"],
78
+ ["ejection fraction", "FR"]
79
+ ]
80
+
81
+ codes_series =
82
+ dataframe
83
+ |> Explorer.DataFrame.pull("text")
84
+ |> Explorer.Series.downcase()
85
+ |> Explorer.Series.transform(fn element ->
86
+ Enum.flat_map(procedure_code_mapping, fn [term, code] ->
87
+ case String.contains?(element, term) do
88
+ true -> [code]
89
+ false -> []
90
+ end
91
+ end)
92
+ end)
93
+
94
+ dataframe
95
+ |> Explorer.DataFrame.put("codes", codes_series)
96
+ ```
livebooks/using_audio_tagger_library.livemd ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!-- livebook:{"app_settings":{"auto_shutdown_ms":5000,"multi_session":true,"show_source":true,"slug":"transcriber"}} -->
2
+
3
+ # Tag Audio
4
+
5
+ ```elixir
6
+ Mix.install(
7
+ [
8
+ {:audio_tagger, path: "./development/ml/audio_tagger"},
9
+ {:kino_bumblebee, "~> 0.4.0"},
10
+ {:exla, ">= 0.0.0"},
11
+ {:explorer, "~> 0.7.0"},
12
+ {:kino_explorer, "~> 0.1.11"}
13
+ ],
14
+ config: [
15
+ nx: [default_backend: EXLA.Backend]
16
+ # exla: [
17
+ # clients: [
18
+ # cuda: [
19
+ # platform: :cuda,
20
+ # lazy_transfers: :never
21
+ # ]
22
+ # ]
23
+ # ]
24
+ ]
25
+ )
26
+ ```
27
+
28
+ ## Step 1: Create Vector Embeddings for ICD-9 Codes
29
+
30
+ ```elixir
31
+ # Use sentence-transformers/all-MiniLM-L6-v2 to create vectors for each medical code description
32
+ tmpfile = Path.join(System.tmp_dir(), "CMS32_DESC_LONG_SHORT_DX")
33
+
34
+ AudioTagger.Vectors.precalculate(tmpfile)
35
+ ```
36
+
37
+ ## Step 2: Transcribe Audio Recording
38
+
39
+ ```elixir
40
+ # 1 - Prepare model and choose audio file
41
+ featurizer = AudioTagger.Transcriber.prepare_featurizer()
42
+
43
+ audio_input = Kino.Input.audio("Audio", sampling_rate: featurizer.sampling_rate)
44
+ ```
45
+
46
+ ```elixir
47
+ # 2 - Transcribe audio recording to text using OpenAI's Whisper model (takes approximately a minute on an M1 Max)
48
+ chosen_audio = Kino.Input.read(audio_input)
49
+
50
+ if chosen_audio == nil do
51
+ raise "No file chosen. Please select a file in the widget above."
52
+ end
53
+
54
+ file = chosen_audio.file_ref |> Kino.Input.file_path() |> File.read!()
55
+ options = [model_name: "openai/whisper-tiny", num_channels: chosen_audio.num_channels]
56
+
57
+ transcription_df =
58
+ AudioTagger.Transcriber.transcribe_audio(featurizer, file, options)
59
+ |> Enum.map(&Function.identity/1)
60
+ |> Explorer.DataFrame.new()
61
+ ```
62
+
63
+ ## Step 3: Tag Transcribed Audio
64
+
65
+ ```elixir
66
+ labels_df =
67
+ "#{tmpfile}.csv"
68
+ |> Explorer.DataFrame.from_csv!(
69
+ dtypes: [
70
+ {"DIAGNOSIS CODE", :string},
71
+ {"LONG DESCRIPTION", :string},
72
+ {"SHORT DESCRIPTION", :string}
73
+ ]
74
+ )
75
+ |> Explorer.DataFrame.select([0, 1, 2])
76
+ |> Explorer.DataFrame.rename(["code", "long_description", "short_description"])
77
+
78
+ tagged_audio =
79
+ transcription_df
80
+ |> AudioTagger.Classifier.SemanticSearch.tag(
81
+ labels_df,
82
+ "#{tmpfile}.bin"
83
+ )
84
+ ```