Refactor code

This commit is contained in:
Alex Lion
2026-08-04 14:10:12 +07:00
parent 44324495d8
commit 15901e7cd9
5 changed files with 146 additions and 131 deletions

View File

@@ -60,7 +60,9 @@ defmodule Claper.Transcriptions.MistralRealtimeClient do
@impl true
def handle_info(:send_session_update, state) do
session_config = %{"audio_format" => %{"encoding" => "pcm_s16le", "sample_rate" => 16000}}
session_config = %{
"audio_format" => %{"encoding" => "pcm_s16le", "sample_rate" => 16_000}
}
message = Jason.encode!(%{"type" => "session.update", "session" => session_config})
{:reply, {:text, message}, state}
@@ -74,47 +76,8 @@ defmodule Claper.Transcriptions.MistralRealtimeClient do
@impl true
def handle_frame({:text, msg}, state) do
case Jason.decode(msg) do
{:ok, %{"type" => "session.created"} = event} ->
Logger.info("MistralRealtimeClient: session created")
send(state.callback_pid, {:mistral_event, :session_created, event})
{:ok, %{state | session_ready: true}}
{:ok, %{"type" => "session.updated"}} ->
Logger.info("MistralRealtimeClient: session updated, ready for audio")
{:ok, state}
{:ok, %{"type" => "transcription.text.delta", "text" => text}} ->
send(state.callback_pid, {:mistral_event, :text_delta, text})
{:ok, state}
{:ok, %{"type" => "transcription.segment", "text" => text}} ->
send(state.callback_pid, {:mistral_event, :segment, text})
{:ok, state}
{:ok, %{"type" => "transcription.done"} = event} ->
text = Map.get(event, "text", "")
send(state.callback_pid, {:mistral_event, :done, text})
{:ok, state}
{:ok, %{"type" => "transcription.language"} = event} ->
lang = Map.get(event, "audioLanguage") || Map.get(event, "language")
Logger.info("MistralRealtimeClient: detected language #{lang}")
send(state.callback_pid, {:mistral_event, :language, lang})
{:ok, state}
{:ok, %{"type" => "error"} = event} ->
error_msg = get_in(event, ["error", "message"]) || "unknown error"
Logger.error("MistralRealtimeClient: error - #{error_msg}")
send(state.callback_pid, {:mistral_event, :error, error_msg})
{:ok, state}
{:ok, event} ->
Logger.info(
"MistralRealtimeClient: unhandled event type #{inspect(event["type"])} payload=#{inspect(event)}"
)
{:ok, state}
handle_event(event, state)
{:error, reason} ->
Logger.error("MistralRealtimeClient: failed to parse: #{inspect(reason)}")
@@ -134,6 +97,56 @@ defmodule Claper.Transcriptions.MistralRealtimeClient do
{:reconnect, state}
end
defp handle_event(%{"type" => "session.created"} = event, state) do
Logger.info("MistralRealtimeClient: session created")
send(state.callback_pid, {:mistral_event, :session_created, event})
{:ok, %{state | session_ready: true}}
end
defp handle_event(%{"type" => "session.updated"}, state) do
Logger.info("MistralRealtimeClient: session updated, ready for audio")
{:ok, state}
end
defp handle_event(%{"type" => "transcription.text.delta", "text" => text}, state) do
send(state.callback_pid, {:mistral_event, :text_delta, text})
{:ok, state}
end
defp handle_event(%{"type" => "transcription.segment", "text" => text}, state) do
send(state.callback_pid, {:mistral_event, :segment, text})
{:ok, state}
end
defp handle_event(%{"type" => "transcription.done"} = event, state) do
text = Map.get(event, "text", "")
send(state.callback_pid, {:mistral_event, :done, text})
{:ok, state}
end
defp handle_event(%{"type" => "transcription.language"} = event, state) do
lang = Map.get(event, "audioLanguage") || Map.get(event, "language")
Logger.info("MistralRealtimeClient: detected language #{lang}")
send(state.callback_pid, {:mistral_event, :language, lang})
{:ok, state}
end
defp handle_event(%{"type" => "error"} = event, state) do
error_msg = get_in(event, ["error", "message"]) || "unknown error"
Logger.error("MistralRealtimeClient: error - #{error_msg}")
send(state.callback_pid, {:mistral_event, :error, error_msg})
{:ok, state}
end
defp handle_event(event, state) do
Logger.info(
"MistralRealtimeClient: unhandled event type #{inspect(event["type"])} payload=#{inspect(event)}"
)
{:ok, state}
end
defp get_api_key do
Claper.Settings.get_transcription_api_key()
end

View File

@@ -40,10 +40,7 @@ defmodule Claper.Transcriptions.TranscriptionWorker do
@impl true
def init({event_uuid, presentation_file_id}) do
unless Claper.Settings.transcription_globally_enabled?() do
Logger.info("TranscriptionWorker: transcription globally disabled, not starting")
{:stop, :transcription_disabled}
else
if Claper.Settings.transcription_globally_enabled?() do
Logger.info("TranscriptionWorker started for event #{event_uuid}")
config_language =
@@ -72,6 +69,9 @@ defmodule Claper.Transcriptions.TranscriptionWorker do
Logger.error("Failed to connect to Mistral realtime API: #{inspect(reason)}")
{:stop, reason}
end
else
Logger.info("TranscriptionWorker: transcription globally disabled, not starting")
{:stop, :transcription_disabled}
end
end

View File

@@ -106,11 +106,9 @@ defmodule ClaperWeb.AdminLive.EventLive do
transcriptions = socket.assigns.transcriptions
content =
transcriptions
|> Enum.map(fn t ->
Enum.map_join(transcriptions, "\n", fn t ->
"[#{Calendar.strftime(t.inserted_at, "%Y-%m-%d %H:%M:%S")}] #{t.text}"
end)
|> Enum.join("\n")
{:noreply,
push_event(socket, "download_csv", %{

View File

@@ -26,91 +26,95 @@ defmodule ClaperWeb.EventLive.Manage do
|> put_flash(:error, gettext("Event doesn't exist"))
|> redirect(to: "/")}
else
if connected?(socket) do
Claper.Events.Event.subscribe(event.uuid)
Presentations.subscribe(event.presentation_file.id)
Events.subscribe_user_events(socket.assigns.current_user.id)
end
posts = list_all_posts(socket, event.uuid)
pinned_posts = list_pinned_posts(socket, event.uuid)
questions = list_all_questions(socket, event.uuid)
form_submits = list_form_submits(socket, event.presentation_file.id)
audio_token =
Phoenix.Token.sign(ClaperWeb.Endpoint, "audio_token", %{
user_id: socket.assigns.current_user.id,
event_uuid: event.uuid
})
transcription_config =
Transcriptions.get_transcription_config(event.presentation_file.id)
transcription_globally_enabled = Claper.Settings.transcription_globally_enabled?()
# Auto-start transcription worker if config says enabled and globally enabled
if connected?(socket) && transcription_globally_enabled && transcription_config &&
transcription_config.enabled do
unless Claper.Transcriptions.TranscriptionWorker.running?(event.uuid) do
DynamicSupervisor.start_child(
Claper.TranscriptionSupervisor,
{Claper.Transcriptions.TranscriptionWorker, {event.uuid, event.presentation_file.id}}
)
end
end
socket =
socket
|> assign(:interaction_modal, false)
|> assign(:settings_modal, false)
|> assign(:attendees_nb, 0)
|> assign(:event, event)
|> assign(:sort_questions_by, "date")
|> assign(:state, event.presentation_file.presentation_state)
|> assign(:audio_token, audio_token)
|> assign(:transcription_config, transcription_config)
|> assign(:transcription_globally_enabled, transcription_globally_enabled)
|> stream(:posts, posts)
|> stream(:questions, questions)
|> stream(:pinned_posts, pinned_posts)
|> stream(:form_submits, form_submits)
|> assign(:pinned_post_count, length(pinned_posts))
|> assign(:question_count, length(questions))
|> assign(:post_count, length(posts))
|> assign(
:total_interactions,
Claper.Interactions.get_number_total_interactions(event.presentation_file.id)
)
|> assign(
:form_submit_count,
length(form_submits)
)
|> assign(:create, nil)
|> assign(:list_tab, :posts)
|> assign(:create_action, :new)
|> assign(
:missing_slide_thumbnails,
Presentations.missing_slide_thumbnails?(event.presentation_file)
)
|> assign(:thumbnail_cache_bust, thumbnail_cache_bust())
|> assign(:thumbnail_regeneration_in_progress, false)
|> push_event("page-manage", %{
current_page: event.presentation_file.presentation_state.position,
timeout: 500
})
|> then(fn s ->
if transcription_config && transcription_config.enabled do
push_event(s, "transcription-state", %{enabled: true})
else
s
end
end)
|> interactions_at_position(event.presentation_file.presentation_state.position)
{:ok, socket}
mount_event(socket, event)
end
end
defp mount_event(socket, event) do
if connected?(socket) do
Claper.Events.Event.subscribe(event.uuid)
Presentations.subscribe(event.presentation_file.id)
Events.subscribe_user_events(socket.assigns.current_user.id)
end
posts = list_all_posts(socket, event.uuid)
pinned_posts = list_pinned_posts(socket, event.uuid)
questions = list_all_questions(socket, event.uuid)
form_submits = list_form_submits(socket, event.presentation_file.id)
audio_token =
Phoenix.Token.sign(ClaperWeb.Endpoint, "audio_token", %{
user_id: socket.assigns.current_user.id,
event_uuid: event.uuid
})
transcription_config =
Transcriptions.get_transcription_config(event.presentation_file.id)
transcription_globally_enabled = Claper.Settings.transcription_globally_enabled?()
# Auto-start transcription worker if config says enabled and globally enabled
if connected?(socket) && transcription_globally_enabled && transcription_config &&
transcription_config.enabled do
unless Claper.Transcriptions.TranscriptionWorker.running?(event.uuid) do
DynamicSupervisor.start_child(
Claper.TranscriptionSupervisor,
{Claper.Transcriptions.TranscriptionWorker, {event.uuid, event.presentation_file.id}}
)
end
end
socket =
socket
|> assign(:interaction_modal, false)
|> assign(:settings_modal, false)
|> assign(:attendees_nb, 0)
|> assign(:event, event)
|> assign(:sort_questions_by, "date")
|> assign(:state, event.presentation_file.presentation_state)
|> assign(:audio_token, audio_token)
|> assign(:transcription_config, transcription_config)
|> assign(:transcription_globally_enabled, transcription_globally_enabled)
|> stream(:posts, posts)
|> stream(:questions, questions)
|> stream(:pinned_posts, pinned_posts)
|> stream(:form_submits, form_submits)
|> assign(:pinned_post_count, length(pinned_posts))
|> assign(:question_count, length(questions))
|> assign(:post_count, length(posts))
|> assign(
:total_interactions,
Claper.Interactions.get_number_total_interactions(event.presentation_file.id)
)
|> assign(
:form_submit_count,
length(form_submits)
)
|> assign(:create, nil)
|> assign(:list_tab, :posts)
|> assign(:create_action, :new)
|> assign(
:missing_slide_thumbnails,
Presentations.missing_slide_thumbnails?(event.presentation_file)
)
|> assign(:thumbnail_cache_bust, thumbnail_cache_bust())
|> assign(:thumbnail_regeneration_in_progress, false)
|> push_event("page-manage", %{
current_page: event.presentation_file.presentation_state.position,
timeout: 500
})
|> then(fn s ->
if transcription_config && transcription_config.enabled do
push_event(s, "transcription-state", %{enabled: true})
else
s
end
end)
|> interactions_at_position(event.presentation_file.presentation_state.position)
{:ok, socket}
end
defp leader?(%{assigns: %{current_user: current_user}} = _socket, event) do
Claper.Events.led_by?(current_user.email, event) || event.user.id == current_user.id
end

View File

@@ -12,7 +12,7 @@ defmodule Claper.Transcriptions.MistralRealtimeClientTest do
assert %{
"type" => "session.update",
"session" => %{
"audio_format" => %{"encoding" => "pcm_s16le", "sample_rate" => 16000}
"audio_format" => %{"encoding" => "pcm_s16le", "sample_rate" => 16_000}
}
} = Jason.decode!(message)