mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-06-25 08:48:13 +02:00
chore: refactor and add tests (#130)
* chore: add tests for end call * Update pipecat module * fix: allow interruptions from deepgram flux * Add VadUserTurnStrategy * chore: add test for voicemail detection
This commit is contained in:
parent
2aedb839ff
commit
033fde8946
15 changed files with 2106 additions and 542 deletions
|
|
@ -10,16 +10,13 @@ from api.services.pipecat.in_memory_buffers import (
|
|||
InMemoryTranscriptBuffer,
|
||||
)
|
||||
from api.services.pipecat.pipeline_metrics_aggregator import PipelineMetricsAggregator
|
||||
from api.services.workflow.disposition_mapper import (
|
||||
apply_disposition_mapping,
|
||||
get_organization_id_from_workflow_run,
|
||||
)
|
||||
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, LLMContextFrame
|
||||
from pipecat.pipeline.task import PipelineTask
|
||||
from pipecat.processors.audio.audio_buffer_processor import AudioBufferProcessor
|
||||
from pipecat.utils.enums import EndTaskReason
|
||||
|
||||
|
||||
def register_event_handlers(
|
||||
|
|
@ -83,18 +80,17 @@ def register_event_handlers(
|
|||
@transport.event_handler("on_client_disconnected")
|
||||
async def on_client_disconnected(_transport, _participant):
|
||||
call_disposed = engine.is_call_disposed()
|
||||
|
||||
logger.debug(
|
||||
f"In on_client_disconnected callback handler. Call disposed: {call_disposed}"
|
||||
)
|
||||
engine.handle_client_disconnected()
|
||||
|
||||
# Stop recordings
|
||||
await audio_buffer.stop_recording()
|
||||
|
||||
# Only cancel the task if the call is not already disposed by the engine
|
||||
if not call_disposed:
|
||||
await task.cancel()
|
||||
# End the call
|
||||
await engine.end_call_with_reason(
|
||||
EndTaskReason.USER_HANGUP.value, abort_immediately=True
|
||||
)
|
||||
|
||||
@task.event_handler("on_pipeline_started")
|
||||
async def on_pipeline_started(_task: PipelineTask, _frame: Frame):
|
||||
|
|
@ -114,9 +110,6 @@ def register_event_handlers(
|
|||
# Stop recordings
|
||||
await audio_buffer.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()
|
||||
|
||||
# Add trace URL if available (must be done before conversation tracing ends)
|
||||
|
|
@ -129,13 +122,6 @@ def register_event_handlers(
|
|||
# also consider existing gathered context in workflow_run
|
||||
gathered_context = {**gathered_context, **workflow_run.gathered_context}
|
||||
|
||||
organization_id = await get_organization_id_from_workflow_run(workflow_run_id)
|
||||
mapped_call_disposition = await apply_disposition_mapping(
|
||||
call_disposition, organization_id
|
||||
)
|
||||
|
||||
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", [])
|
||||
|
|
|
|||
|
|
@ -57,6 +57,10 @@ def build_pipeline(
|
|||
# Insert voicemail detector after STT if enabled
|
||||
# Note: We intentionally do NOT use voicemail_detector.gate() to allow TTS
|
||||
# frames to continue flowing during classification (non-blocking detection)
|
||||
|
||||
# Note: We must keep user_context_aggregator after voicemail_detector
|
||||
# or else, LLMContextFrames generated from user_context_aggregator will
|
||||
# start generating LLM Completion from Voicemail Classifier
|
||||
if voicemail_detector:
|
||||
logger.info("Adding native voicemail detector to pipeline")
|
||||
processors.append(voicemail_detector.detector())
|
||||
|
|
|
|||
|
|
@ -52,9 +52,11 @@ from pipecat.processors.aggregators.llm_response_universal import (
|
|||
LLMUserAggregatorParams,
|
||||
)
|
||||
from pipecat.transports.smallwebrtc.connection import SmallWebRTCConnection
|
||||
from pipecat.turns.user_mute import MuteUntilFirstBotCompleteUserMuteStrategy
|
||||
from pipecat.turns.user_mute import (
|
||||
CallbackUserMuteStrategy,
|
||||
MuteUntilFirstBotCompleteUserMuteStrategy,
|
||||
)
|
||||
from pipecat.turns.user_start import (
|
||||
ExternalUserTurnStartStrategy,
|
||||
TranscriptionUserTurnStartStrategy,
|
||||
)
|
||||
from pipecat.turns.user_start.vad_user_turn_start_strategy import (
|
||||
|
|
@ -547,7 +549,7 @@ async def _run_pipeline(
|
|||
|
||||
if is_deepgram_flux:
|
||||
user_turn_strategies = UserTurnStrategies(
|
||||
start=[VADUserTurnStartStrategy(), ExternalUserTurnStartStrategy()],
|
||||
start=[VADUserTurnStartStrategy(), TranscriptionUserTurnStartStrategy()],
|
||||
stop=[ExternalUserTurnStopStrategy()],
|
||||
)
|
||||
else:
|
||||
|
|
@ -556,9 +558,16 @@ async def _run_pipeline(
|
|||
stop=[TranscriptionUserTurnStopStrategy()],
|
||||
)
|
||||
|
||||
# Create user mute strategies
|
||||
# - CallbackUserMuteStrategy: mutes based on engine's _mute_pipeline state
|
||||
user_mute_strategies = [
|
||||
MuteUntilFirstBotCompleteUserMuteStrategy(),
|
||||
CallbackUserMuteStrategy(should_mute_callback=engine.should_mute_user),
|
||||
]
|
||||
|
||||
user_params = LLMUserAggregatorParams(
|
||||
user_turn_strategies=user_turn_strategies,
|
||||
user_mute_strategies=[MuteUntilFirstBotCompleteUserMuteStrategy()],
|
||||
user_mute_strategies=user_mute_strategies,
|
||||
user_idle_timeout=max_user_idle_timeout,
|
||||
)
|
||||
context_aggregator = LLMContextAggregatorPair(
|
||||
|
|
@ -606,7 +615,7 @@ async def _run_pipeline(
|
|||
@voicemail_detector.event_handler("on_voicemail_detected")
|
||||
async def _on_voicemail_detected(_processor):
|
||||
logger.info(f"Voicemail detected for workflow run {workflow_run_id}")
|
||||
await engine.send_end_task_frame(
|
||||
await engine.end_call_with_reason(
|
||||
reason=EndTaskReason.VOICEMAIL_DETECTED.value,
|
||||
abort_immediately=True,
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue