|
<!-- livebook:{"app_settings":{"access_type":"public","slug":"whisper-chat"}} --> |
|
|
|
|
|
|
|
```elixir |
|
Mix.install( |
|
[ |
|
{:kino_bumblebee, "~> 0.2.1"}, |
|
{:exla, "~> 0.5.1"} |
|
], |
|
config: [nx: [default_backend: EXLA.Backend]] |
|
) |
|
``` |
|
|
|
|
|
|
|
```elixir |
|
Kino.Markdown.new(""" |
|
This chat is open to anyone, be polite and act responsibly. :) Note chat history has been disabled. |
|
""") |
|
``` |
|
|
|
```elixir |
|
{:ok, model_info} = |
|
Bumblebee.load_model({:hf, "openai/whisper-tiny"}, log_params_diff: false) |
|
|
|
{:ok, featurizer} = Bumblebee.load_featurizer({:hf, "openai/whisper-tiny"}) |
|
{:ok, tokenizer} = Bumblebee.load_tokenizer({:hf, "openai/whisper-tiny"}) |
|
|
|
serving = |
|
Bumblebee.Audio.speech_to_text(model_info, featurizer, tokenizer, |
|
max_new_tokens: 100, |
|
compile: [batch_size: 8], |
|
defn_options: [compiler: EXLA] |
|
) |
|
|
|
Kino.start_child({Nx.Serving, serving: serving, name: WhisperChat}) |
|
``` |
|
|
|
```elixir |
|
audio_input = Kino.Input.audio("Audio", sampling_rate: featurizer.sampling_rate) |
|
name_input = Kino.Input.text("Name") |
|
form = Kino.Control.form([name: name_input, audio: audio_input], submit: "Send") |
|
frame = Kino.Frame.new() |
|
|
|
Kino.async_listen(form, fn %{data: %{audio: audio, name: name}, origin: origin} -> |
|
if audio && name != "" do |
|
audio = |
|
audio.data |
|
|> Nx.from_binary(:f32) |
|
|> Nx.reshape({:auto, audio.num_channels}) |
|
|> Nx.mean(axes: [1]) |
|
|
|
%{results: [%{text: generated_text}]} = Nx.Serving.batched_run(WhisperChat, audio) |
|
content = Kino.Markdown.new("**#{name}**: #{generated_text}") |
|
Kino.Frame.append(frame, content, temporary: true) |
|
else |
|
content = Kino.Markdown.new("*Error! Name and Audio are required*") |
|
Kino.Frame.append(frame, content, to: origin) |
|
end |
|
end) |
|
|
|
Kino.Layout.grid([frame, form], boxed: true, gap: 16) |
|
``` |
|
|