mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-06-22 08:38:13 +02:00
on_client_disconnect only when user disconnects.
This commit is contained in:
parent
70c58e1a40
commit
33ff3b9779
11 changed files with 162 additions and 214 deletions
|
|
@ -1,9 +1,8 @@
|
|||
from typing import Optional
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from api.db import db_client
|
||||
from api.services.campaign.call_dispatcher import campaign_call_dispatcher
|
||||
from api.services.pipecat.audio_config import AudioConfig
|
||||
from api.services.pipecat.audio_transcript_buffers import (
|
||||
InMemoryAudioBuffer,
|
||||
InMemoryTranscriptBuffer,
|
||||
|
|
@ -16,20 +15,20 @@ from api.services.workflow.disposition_mapper import (
|
|||
from api.services.workflow.pipecat_engine import PipecatEngine
|
||||
from api.tasks.arq import enqueue_job
|
||||
from api.tasks.function_names import FunctionNames
|
||||
from pipecat.frames.frames import Frame
|
||||
from pipecat.pipeline.task import PipelineTask
|
||||
from pipecat.transports.base_transport import BaseTransport
|
||||
from pipecat.utils.enums import EndTaskReason
|
||||
from pipecat.processors.audio.audio_buffer_processor import AudioBuffer
|
||||
from pipecat.processors.audio.audio_synchronizer import AudioSynchronizer
|
||||
|
||||
|
||||
def register_transport_event_handlers(
|
||||
task: PipelineTask,
|
||||
transport,
|
||||
workflow_run_id,
|
||||
audio_buffer,
|
||||
task: PipelineTask,
|
||||
engine: PipecatEngine,
|
||||
usage_metrics_aggregator: PipelineMetricsAggregator,
|
||||
audio_synchronizer=None,
|
||||
audio_config=None,
|
||||
audio_buffer: AudioBuffer,
|
||||
audio_synchronizer: AudioSynchronizer,
|
||||
audio_config=AudioConfig,
|
||||
):
|
||||
"""Register event handlers for transport events"""
|
||||
|
||||
|
|
@ -58,52 +57,55 @@ def register_transport_event_handlers(
|
|||
await engine.initialize()
|
||||
|
||||
@transport.event_handler("on_client_disconnected")
|
||||
async def on_client_disconnected(
|
||||
transport: BaseTransport,
|
||||
participant,
|
||||
transport_disconnect_reason: Optional[str] = None,
|
||||
async def on_client_disconnected(transport, participant):
|
||||
logger.debug("In on_client_disconnected callback handler")
|
||||
await engine.handle_client_disconnected()
|
||||
|
||||
# Stop recordings
|
||||
await audio_buffer.stop_recording()
|
||||
if audio_synchronizer:
|
||||
await audio_synchronizer.stop_recording()
|
||||
|
||||
# Cancel the task since the client is disconnected
|
||||
await task.cancel()
|
||||
|
||||
# Return the buffers so they can be passed to other handlers
|
||||
return in_memory_audio_buffer, in_memory_transcript_buffer
|
||||
|
||||
|
||||
def register_task_event_handler(
|
||||
workflow_run_id: int,
|
||||
engine: PipecatEngine,
|
||||
task: PipelineTask,
|
||||
transport,
|
||||
audio_buffer: AudioBuffer,
|
||||
audio_synchronizer: AudioSynchronizer,
|
||||
in_memory_audio_buffer: InMemoryAudioBuffer,
|
||||
in_memory_transcript_buffer: InMemoryTranscriptBuffer,
|
||||
pipeline_metrics_aggregator: PipelineMetricsAggregator,
|
||||
):
|
||||
@task.event_handler("on_pipeline_finished")
|
||||
async def on_pipeline_finished(
|
||||
task: PipelineTask,
|
||||
frame: Frame,
|
||||
):
|
||||
logger.debug(
|
||||
f"In on_client_disconnected callback handler, disconnect_reason: {transport_disconnect_reason}"
|
||||
)
|
||||
logger.debug(f"In on_pipeline_finished callback handler")
|
||||
|
||||
workflow_run = await db_client.get_workflow_run_by_id(workflow_run_id)
|
||||
|
||||
# First priority: Check if engine has a disconnect reason (local disconnect)
|
||||
engine_call_disposition = engine.get_call_disposition()
|
||||
gathered_context = engine.get_gathered_context()
|
||||
# Stop recordings
|
||||
await audio_buffer.stop_recording()
|
||||
if audio_synchronizer:
|
||||
await audio_synchronizer.stop_recording()
|
||||
|
||||
call_disposition = await engine.get_call_disposition()
|
||||
logger.debug(f"call disposition in on_pipeline_finished: {call_disposition}")
|
||||
|
||||
gathered_context = await engine.get_gathered_context()
|
||||
|
||||
# also consider existing gathered context in workflow_run
|
||||
gathered_context = {**gathered_context, **workflow_run.gathered_context}
|
||||
|
||||
if engine_call_disposition:
|
||||
# Engine has set a disconnect reason - this takes priority
|
||||
call_disposition = engine_call_disposition
|
||||
logger.debug(f"Engine disposition detected, code: {call_disposition}")
|
||||
elif transport_disconnect_reason:
|
||||
# TODO: Make this more generic using some DSL or equivalent. This is currently
|
||||
# configured to work for Kapil's bot
|
||||
call_duration = usage_metrics_aggregator.get_call_duration()
|
||||
if transport_disconnect_reason == EndTaskReason.USER_HANGUP.value:
|
||||
if call_duration < 10:
|
||||
call_disposition = "HU"
|
||||
else:
|
||||
call_disposition = "NIBP"
|
||||
else:
|
||||
# Transport provided a disconnect reason (remote hangup)
|
||||
call_disposition = transport_disconnect_reason
|
||||
logger.debug(
|
||||
f"Remote disconnect detected, reason: {call_disposition} duration: {call_duration}"
|
||||
)
|
||||
else:
|
||||
# No reason provided - assume user hangup
|
||||
call_disposition = EndTaskReason.UNKNOWN.value
|
||||
logger.debug("No disposition found from either engine or transport")
|
||||
|
||||
# Cancel task only when no engine disconnect reason (remote disconnect)
|
||||
if not engine_call_disposition:
|
||||
await task.cancel()
|
||||
|
||||
organization_id = await get_organization_id_from_workflow_run(workflow_run_id)
|
||||
mapped_call_disposition = await apply_disposition_mapping(
|
||||
call_disposition, organization_id
|
||||
|
|
@ -111,6 +113,7 @@ def register_transport_event_handlers(
|
|||
|
||||
gathered_context.update({"mapped_call_disposition": mapped_call_disposition})
|
||||
|
||||
# Set user_speech call tag
|
||||
if in_memory_transcript_buffer:
|
||||
call_tags = gathered_context.get("call_tags", [])
|
||||
|
||||
|
|
@ -132,10 +135,6 @@ def register_transport_event_handlers(
|
|||
# Clean up engine resources (including voicemail detector)
|
||||
await engine.cleanup()
|
||||
|
||||
await audio_buffer.stop_recording()
|
||||
if audio_synchronizer:
|
||||
await audio_synchronizer.stop_recording()
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Close Smart-Turn WebSocket if the transport's analyzer supports it
|
||||
# ------------------------------------------------------------------
|
||||
|
|
@ -163,7 +162,7 @@ def register_transport_event_handlers(
|
|||
except Exception as exc:
|
||||
logger.warning(f"Failed to close Smart-Turn analyzer gracefully: {exc}")
|
||||
|
||||
usage_info = usage_metrics_aggregator.get_all_usage_metrics_serialized()
|
||||
usage_info = pipeline_metrics_aggregator.get_all_usage_metrics_serialized()
|
||||
|
||||
logger.debug(f"Usage metrics: {usage_info}")
|
||||
|
||||
|
|
@ -209,9 +208,6 @@ def register_transport_event_handlers(
|
|||
FunctionNames.RUN_INTEGRATIONS_POST_WORKFLOW_RUN, workflow_run_id
|
||||
)
|
||||
|
||||
# Return the buffers so they can be passed to other handlers
|
||||
return in_memory_audio_buffer, in_memory_transcript_buffer
|
||||
|
||||
|
||||
def register_audio_data_handler(
|
||||
audio_synchronizer, workflow_run_id, in_memory_buffer: InMemoryAudioBuffer
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ from api.services.pipecat.engine_pre_aggregator_processor import (
|
|||
)
|
||||
from api.services.pipecat.event_handlers import (
|
||||
register_audio_data_handler,
|
||||
register_task_event_handler,
|
||||
register_transcript_handler,
|
||||
register_transport_event_handlers,
|
||||
)
|
||||
|
|
@ -361,16 +362,28 @@ async def _run_pipeline(
|
|||
# Register event handlers
|
||||
in_memory_audio_buffer, in_memory_transcript_buffer = (
|
||||
register_transport_event_handlers(
|
||||
task,
|
||||
transport,
|
||||
workflow_run_id,
|
||||
audio_buffer,
|
||||
task,
|
||||
engine=engine,
|
||||
usage_metrics_aggregator=pipeline_metrics_aggregator,
|
||||
audio_buffer=audio_buffer,
|
||||
audio_synchronizer=audio_synchronizer,
|
||||
audio_config=audio_config,
|
||||
)
|
||||
)
|
||||
|
||||
register_task_event_handler(
|
||||
workflow_run_id,
|
||||
engine,
|
||||
task,
|
||||
transport,
|
||||
audio_buffer,
|
||||
audio_synchronizer,
|
||||
in_memory_audio_buffer,
|
||||
in_memory_transcript_buffer,
|
||||
pipeline_metrics_aggregator,
|
||||
)
|
||||
|
||||
register_audio_data_handler(
|
||||
audio_synchronizer, workflow_run_id, in_memory_audio_buffer
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue