Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ending Twilio call doesnt work #728

Closed
Vortigern-source opened this issue Nov 17, 2024 · 11 comments
Closed

Ending Twilio call doesnt work #728

Vortigern-source opened this issue Nov 17, 2024 · 11 comments

Comments

@Vortigern-source
Copy link

Description

Is this reporting a bug or feature request?
Bug

If reporting a bug, please fill out the following:

Environment

  • pipecat-ai version: 0.0.49
  • python version: 3.11
  • OS: Linux

Issue description

Provide a clear description of the issue.

Trying to end call from the bot side doesnt end the call. It just ends the websocket connection with causes the call to stay on. It should ideally end the call as in hang it up.

Function used:

`import os
from twilio.rest import Client
from pipecat.frames.frames import EndFrame, TTSSpeakFrame, EndTaskFrame
from pipecat.processors.frame_processor import FrameDirection

async def hangup_call(function_name, tool_call_id, args, llm, context, result_callback):
print("End call function called")
print(f"Function name: {function_name}")
print(f"Context: {context}")
for key, value in args.items():
print(f"{key}: {value}")

await llm.push_frame(EndTaskFrame(), FrameDirection.UPSTREAM)`

Repro steps

List the steps to reproduce the issue.

Expected behavior

Call Should be hung / ended.

Actual behavior

The call isnt being ended, instead it just ends the websocket connection and the call is still connected.

Logs

@omalave
Copy link

omalave commented Nov 18, 2024

I encountered the same issue with:

await llm.push_frame(EndTaskFrame(), FrameDirection.UPSTREAM)

So, I had to create a function and ask the bot to execute it with function calling:

async def hangup_call(function_name, tool_call_id, args, llm, context, result_callback):
    url = f"https://api.twilio.com/2010-04-01/Accounts/{TWILIO_ACCOUNT_SID}/Calls/{call_sid}.json"
    data = {"Status": "completed"}

    response = requests.post(
        url,
        data=data,
        auth=HTTPBasicAuth(TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN),
    )

    # Check the response
    if response.status_code == 200:
        print(f"Call ended successfully: {call_sid}.")
    else:
        print(f"Error ending call: {response.status_code} - {response.text}")

    await result_callback()

However, with this approach, I always had to say "bye" to trigger the function. I haven't managed to make the bot trigger it when needed automatically.

@Vortigern-source
Copy link
Author

But if you tell the bot to use the function wont it use it automatically?

@omalave
Copy link

omalave commented Nov 18, 2024

Well, I have made some progress on this. I got the bot to trigger the function, but it happens before the bot says goodbye. So far, this is what I have:

The bot says hello.
I say hello.
The bot calls the function to end the Twilio call.
The bot says goodbye.

@Vortigern-source
Copy link
Author

Where have you put this function code? is it in the bot.py? Im not sure how to pass the call_sid variable.

@markbackman
Copy link
Contributor

Have you tried ending with an EndFrame().

In all of our examples, we should something like this:

task = PipelineTask(pipeline, PipelineParams(allow_interruptions=True))

@transport.event_handler("on_participant_left")
    async def on_participant_left(transport, participant, reason):
        await task.queue_frame(EndFrame())

You should be able to hook into the PipelineTask and queue and EndFrame() to leave. Is that not working?

@Vortigern-source
Copy link
Author

Thats not what we are trying to achieve, This is a function for the bot to hang up a call on its end. This just terminates the web-socket which leads to the call still being live, hence wasting twilio cost

@markbackman
Copy link
Contributor

Sorry, re-reading:

The call isnt being ended, instead it just ends the websocket connection and the call is still connected.

You have to do this via the Twilio API. This isn't a Pipecat functionality at all. Pipecat just connects to a Twilio call via Websocket. @omalave is onto the right thing: #728 (comment).

Your options are:

  1. Bot initiates hang up via function call: The LLM has a function call available that both push an EndFrame() to disconnect the bot and a Twilio API call that hangs up the connection.
  2. Your app initiates hang up directly: Call the Twilio API to hang up in an event handler or driven by logic in your code.

This is possibly outside of the scope of Pipecat as Pipecat doesn't integrate Twilio APIs. Does that make sense?

@Vortigern-source
Copy link
Author

Yeah I thought so, Aleix asked me to raise this as an issue. Sorry If its not related to pipecat.

@markbackman
Copy link
Contributor

markbackman commented Nov 21, 2024

Yeah I thought so, Aleix asked me to raise this as an issue. Sorry If its not related to pipecat.

All good! Aleix is out for a bit, but I'll connect with him when he's back.

I'm going to leave this issue open since it's something we should consider how we can make doing this easier.

@Vortigern-source
Copy link
Author

I encountered the same issue with:

await llm.push_frame(EndTaskFrame(), FrameDirection.UPSTREAM)

So, I had to create a function and ask the bot to execute it with function calling:

async def hangup_call(function_name, tool_call_id, args, llm, context, result_callback):
    url = f"https://api.twilio.com/2010-04-01/Accounts/{TWILIO_ACCOUNT_SID}/Calls/{call_sid}.json"
    data = {"Status": "completed"}

    response = requests.post(
        url,
        data=data,
        auth=HTTPBasicAuth(TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN),
    )

    # Check the response
    if response.status_code == 200:
        print(f"Call ended successfully: {call_sid}.")
    else:
        print(f"Error ending call: {response.status_code} - {response.text}")

    await result_callback()

However, with this approach, I always had to say "bye" to trigger the function. I haven't managed to make the bot trigger it when needed automatically.

Could you share where you implement this, I tried this code and IM getting errors.

@aconchillo
Copy link
Contributor

aconchillo commented Dec 3, 2024

Hi! There has been a discussion on Discord about this. I originally thought we could do it from Pipecat but there's no websocket message in Twilio to end the call so to end the call properly you need to use the Twilio API.

Here's the discord thread and examples on how to use the API:
https://discord.com/channels/1239284677165056021/1303813821055500359/1311841251925950504

Closing this since there's nothing we can do from Pipecat.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants