Skip to content

Commit 94bfacd

Browse files
committed
[WIP] "Warm transfer" demo
1 parent bff6b2b commit 94bfacd

File tree

1 file changed

+40
-14
lines changed

1 file changed

+40
-14
lines changed

examples/static/warm_transfer.py

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -128,21 +128,38 @@ async def start_order() -> StartOrderResult:
128128
return StartOrderResult(status="error")
129129

130130
# Action handlers
131-
async def configure_participants_for_hold_start(action: dict, flow_manager: FlowManager):
132-
"""Configure the participants' settings (send and receive permissions) for when the customer is put on hold."""
131+
async def pre_transferring_to_human_agent(action: dict, flow_manager: FlowManager):
132+
"""Pre-action before starting transferring to the human agent."""
133133
transport: DailyTransport = flow_manager.transport
134134
customer_participant_id = get_customer_participant_id(transport=transport)
135-
135+
136136
# Update the customer:
137137
# - Revoke their canSend permission, causing their mic to mute
138+
if customer_participant_id:
139+
await transport.update_remote_participants(
140+
remote_participants={
141+
customer_participant_id: {
142+
"permissions": {
143+
"canSend": [],
144+
}
145+
}
146+
}
147+
)
148+
149+
# TODO: this should only run after LLM "transferring you to agent" speech is spoken
150+
async def post_transferring_to_human_agent(action: dict, flow_manager: FlowManager):
151+
"""Post-action after starting transferring to the human agent."""
152+
transport: DailyTransport = flow_manager.transport
153+
customer_participant_id = get_customer_participant_id(transport=transport)
154+
155+
# Update the customer:
138156
# - Update their canReceive permission to only be able to hear the bot's hold music; we don't
139157
# want them hearing the bot and the human agent talking
140158
if customer_participant_id:
141159
await transport.update_remote_participants(
142160
remote_participants={
143161
customer_participant_id: {
144162
"permissions": {
145-
"canSend": [],
146163
"canReceive": {
147164
"byUserId": {
148165
"bot": {
@@ -155,15 +172,16 @@ async def configure_participants_for_hold_start(action: dict, flow_manager: Flow
155172
}
156173
)
157174

158-
async def configure_participants_for_hold_end(action: dict, flow_manager: FlowManager):
175+
# TODO: this should only run after LLM "I'm patching you through" speech is spoken
176+
async def post_end_human_agent_conversation(action: dict, flow_manager: FlowManager):
159177
"""Configure the participants' settings (send and receive permissions) for when the customer is taken off of hold."""
160178
transport: DailyTransport = flow_manager.transport
161179
customer_participant_id = get_customer_participant_id(transport=transport)
162180
agent_participant_id = get_human_agent_participant_id(transport=transport)
163181

164182
# Update the customer:
165183
# - Restore their canSend permission, allowing their mic to be unmuted
166-
# - Update their canReceive permission, allowing them hear the human agent
184+
# - Update their canReceive permission, allowing them to hear the human agent
167185
# - Unmute their mic
168186
if customer_participant_id:
169187
await transport.update_remote_participants(
@@ -337,11 +355,17 @@ def create_transferring_to_human_agent_node() -> NodeConfig:
337355
}
338356
],
339357
functions=[],
340-
# TODO: hmm, the post action runs before the above task_messages audio is spoken. that's not what we want.
358+
pre_actions=[
359+
ActionConfig(
360+
type="pre_transferring_to_human_agent",
361+
handler=pre_transferring_to_human_agent
362+
)
363+
],
364+
# TODO: this should only run after LLM "transferring you to agent" speech is spoken
341365
post_actions=[
342366
ActionConfig(
343-
type="configure_participants_for_hold_start",
344-
handler=configure_participants_for_hold_start
367+
type="post_transferring_to_human_agent",
368+
handler=post_transferring_to_human_agent
345369
)
346370
]
347371
)
@@ -407,11 +431,11 @@ def create_end_human_agent_conversation_node() -> NodeConfig:
407431
},
408432
],
409433
functions=[],
410-
# TODO: hmm, the post action runs before the above task_messages audio is spoken. that's not what we want.
434+
# TODO: this should only run after LLM "I'm patching you through" speech is spoken
411435
post_actions=[
412436
ActionConfig(
413-
type="configure_participants_for_hold_end",
414-
handler=configure_participants_for_hold_end
437+
type="post_end_human_agent_conversation",
438+
handler=post_end_human_agent_conversation
415439
),
416440
ActionConfig(type="end_conversation")
417441
]
@@ -600,8 +624,10 @@ async def on_participant_left(transport: DailyTransport, participant: Dict[str,
600624
)
601625
customer_token = await get_customer_token(daily_rest_helper=daily_rest_helper, room_url=room_url)
602626
human_agent_token = await get_human_agent_token(daily_rest_helper=daily_rest_helper, room_url=room_url)
603-
logger.info(f"TO JOIN AS CUSTOMER: {room_url}{'?' if '?' not in room_url else '&'}t={customer_token}")
604-
logger.info(f"TO JOIN AS AGENT: {room_url}{'?' if '?' not in room_url else '&'}t={human_agent_token}")
627+
# TODO: just for local testing; undo below changes
628+
prebuilt_room_url = "https://paulkprebuilt.ngrok.io/hello?domain=paulk&customHost=paulk.ngrok.io&apiHost=paulk.ngrok.io&bypassRegionDetection=true"
629+
logger.info(f"TO JOIN AS CUSTOMER: {prebuilt_room_url}{'?' if '?' not in room_url else '&'}t={customer_token}")
630+
logger.info(f"TO JOIN AS AGENT: {prebuilt_room_url}{'?' if '?' not in room_url else '&'}t={human_agent_token}")
605631

606632
# Run the pipeline
607633
runner = PipelineRunner()

0 commit comments

Comments
 (0)