Files

81 lines
2.8 KiB
Elixir

defmodule WhisperWeb.AudioChannel do
@moduledoc """
Phoenix Channel que gestiona la recepción de audio en tiempo real desde el cliente.
El audio se envía en chunks binarios y se acumula en un buffer temporal (`AudioBuffer`).
Al recibir el evento `"stop_audio"`, todos los chunks se combinan y se guardan como un único archivo WAV final.
"""
use Phoenix.Channel
require Logger
alias Phoenix.PubSub
def join("audio:lobby", _payload, socket) do
ref = socket_id(socket)
Logger.info("Cliente conectado al canal audio:lobby")
{:ok, socket}
end
def handle_in("audio_chunk", {:binary, raw_binary}, socket) do
<<header_len::16, rest::binary>> = raw_binary
<<header::binary-size(header_len), audio::binary>> = rest
%{"sample_rate" => rate} = Jason.decode!(header)
ref = socket_id(socket)
Logger.info("Chunk recibido: #{byte_size(audio)} bytes, sample_rate: #{rate}")
AudioBuffer.append(ref, {rate, audio})
{:ok, path} = AudioSaver.save_chunk_as_wav(ref, audio, rate, "part")
chunk_number = Whisper.Counter.next(ref)
# AudioFilesList.add_file(path)
Task.start(fn ->
transcription = Whisper.SendToModel.realtime(path)
Logger.info("Real-time:\n#{transcription}")
chunk_id = "chunk_#{chunk_number}" # <--- un ID común
message = %{"chunks" => [%{"text" => transcription, "id" => chunk_id}]}
Phoenix.PubSub.broadcast(Whisper.PubSub, "transcription", {:transcription_tiny, Jason.encode!(message)})
transcription_large = Whisper.SendToModel.large(path)
Logger.info("✅ Transcripción completa:\n#{transcription_large}")
message_large = %{"chunks" => [%{"text" => transcription_large, "id" => chunk_id}]}
Phoenix.PubSub.broadcast(Whisper.PubSub, "transcription", {:transcription_large, Jason.encode!(message_large)})
File.rm!(path)
end)
{:noreply, socket}
end
def handle_in("stop_audio", _payload, socket) do
Logger.info("🛑 Grabación detenida por cliente")
# ref = socket_id(socket)
# chunks = AudioBuffer.get_and_clear(ref)
# if chunks != [] do
# [{rate, _} | _] = chunks
# full_audio = Enum.map(chunks, fn {_, bin} -> bin end) |> IO.iodata_to_binary()
# {:ok, path} = AudioSaver.save_chunk_as_wav(ref, full_audio, rate, "final")
# Task.start(fn ->
# transcription = Whisper.SendToModel.large(path)
# Logger.info("✅ Transcripción completa:\n#{transcription}")
# message = %{"chunks" => [%{"text" => transcription}]}
# Phoenix.PubSub.broadcast(Whisper.PubSub, "transcription", {:transcription_m, Jason.encode!(message)})
# # File.rm!(path)
# end)
# end
{:noreply, socket}
end
defp socket_id(socket), do: socket.transport_pid |> :erlang.pid_to_list() |> List.to_string()
end