hubertlepicki

hubertlepicki

Processing uploaded files as they're being uploaded

I have a service that allows for taking voice commands. These voice commands are being recorded through the browser, and are being sent to my Phoenix application.

Once I have the file, I am calling OpenAI Whisper APIs to get the transcription.

This works, but introduces a couple of seconds of lag that I could have avoided if I was smarter about uploading files.

Baiscally, instead of waiting for the Phoenix.Multipart to process the uploaded file fully and save it in the temporary file, I would love to start uploading the received file to Whisper APIs as soon as the first bytes of it hit the server.

Anyone can point me in the right direction?

So far I figured I have the following options:

  1. Disable Plug.Parsers.Multipart altogether for my specific request path, and instead start parsing the request in Phoenix controller and start uploading the file in chunks as I am reading it from input stream

  2. Write a custom Cowboy handler to do the same above (would tie me to Cowboy)

  3. Upload the file over Phoenix.Channel instead

Any other options? maybe there’s a ready to use solution / blog post that my google fu fails to find?

Most Liked

kokolegorille

kokolegorille

There is an example of this in Bumblebee…

https://github.com/elixir-nx/bumblebee/blob/main/examples/phoenix/speech_to_text.exs

In particular…

|> allow_upload(:audio, accept: :any, progress: &handle_progress/3, auto_upload: true)}


  defp handle_progress(:audio, entry, socket) when entry.done? do
    binary =
      consume_uploaded_entry(socket, entry, fn %{path: path} ->
        {:ok, File.read!(path)}
      end)

    # We always pre-process audio on the client into a single channel
    audio = Nx.from_binary(binary, :f32)

    task = Task.async(fn -> Nx.Serving.batched_run(PhoenixDemo.Serving, audio) end)

    {:noreply, assign(socket, task: task)}
  end

As You can see the data is consumed automatically.

It would be nice to be able to detect silence in the js code, and push data when one is detected.

That is one thing the python whisper client does well, clean cut huge audio into smaller part.

mtarnovan

mtarnovan

Maybe you could try writing a Whisper API adapter for minne (see also this post: Alternate :multipart plug parser - S3 storage instead of tmp/)

  1. will work (I worked on a some code recently that replaces Plug.Parsers with a custom implementation that uploads to S3 on the fly, effectively a “streaming upload proxy”). You’ll probably still need to parse multipart requests, so you’ll probably end up copy pasting a lot from Parsers.Multipart

  2. I don’t know much about this, but could work, and could be simpler (i.e. if you can just copy from socket to socket). If you do something like this, I’d love to see some code.

al2o3cr

al2o3cr

Does the Whisper API even start processing if you’re still streaming it an input file?

Without that, I don’t think you’ll get a response any faster by adding all this complexity.

Where Next?

Popular in Questions Top

minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New

Other popular topics Top

nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 31586 112
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
AstonJ
Posting this to see if we can make things easier for people to get into Neovim. If you use Neovim and have a favourite distro please let ...
New

We're in Beta

About us Mission Statement