defmodule ElixirAiWeb.VoiceLive do use ElixirAiWeb, :live_view require Logger def mount(_params, _session, socket) do {:ok, assign(socket, state: :idle, transcription: nil), layout: false} end def render(assigns) do ~H"""
<%= if @state == :idle do %> Voice Input <% end %> <%= if @state == :recording do %> Recording <% end %> <%= if @state == :processing do %> Processing… <% end %> <%= if @state == :transcribed do %> Transcription <% end %>
<%= if @state in [:recording, :processing] do %>
<% end %> <%= if @state == :transcribed do %>

{@transcription}

<% end %> <%= if @state == :idle do %> <% end %> <%= if @state == :recording do %> <% end %> <%= if @state == :transcribed do %> <% end %>
""" end def handle_event("recording_started", _params, socket) do {:noreply, assign(socket, state: :recording)} end def handle_event("audio_recorded", %{"data" => base64, "mime_type" => mime_type}, socket) do case Base.decode64(base64) do {:ok, audio_binary} -> Logger.info( "VoiceLive: received #{byte_size(audio_binary)} bytes of audio (#{mime_type})" ) ElixirAi.AudioProcessing.submit(audio_binary, mime_type, self()) {:noreply, assign(socket, state: :processing)} :error -> Logger.error("VoiceLive: failed to decode base64 audio data") {:noreply, assign(socket, state: :idle)} end end def handle_event("recording_error", %{"reason" => reason}, socket) do Logger.warning("VoiceLive: recording error: #{reason}") {:noreply, assign(socket, state: :idle)} end def handle_event("dismiss_transcription", _params, socket) do {:noreply, assign(socket, state: :idle, transcription: nil)} end def handle_info({:transcription_result, {:ok, text}}, socket) do {:noreply, assign(socket, state: :transcribed, transcription: text)} end def handle_info({:transcription_result, {:error, reason}}, socket) do Logger.error("VoiceLive: transcription failed: #{inspect(reason)}") {:noreply, assign(socket, state: :idle)} end end