> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vocode.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Working with phone calls

> How to use agents with inbound and outbound phone calls.

# Overview

Vocode supports using agents with inbound and outbound phone calls. Users
can [create their own agents](/open-source/create-your-own-agent) and use them
to fulfill a variety of use cases like information collection, appointment scheduling,
sales, customer support, and more.

# Requirements

1. [Ngrok](https://ngrok.com/) (used to host the `TelephonyServer` locally)
2. [ffmpeg](https://ffmpeg.org/)
   a. If you have Homebrew installed, run `brew install ffmpeg`
3. [Redis](https://redis.com/)
   a. If you have Homebrew installed, run `brew install redis`
4. (optional) [Docker](https://www.docker.com/)

# Environments

1. Copy the `.env.template` file and fill in the values of your API keys. You'll need to get API keys for:

* [Deepgram](https://deepgram.com) (for speech transcription)
* [OpenAI](https://platform.openai.com) (for the underlying agent)
* [Azure](https://azure.microsoft.com/en-us/products/cognitive-services/text-to-speech/) (for speech synthesis)
* [Twilio](https://console.twilio.com/) (for telephony)

```bash theme={null}
cp .env.template .env
```

2. Set up hosting so that Twilio can hit your server. An easy way to do this is `ngrok`: in our code we set it up to be running on port 3000, run:

```
ngrok http 3000
```

Copy the URL that is tunneling localhost:3000 to your `.env` without `https://`, e.g.

```
BASE_URL=asdf1234.ngrok.app
```

# Telephony Server

The `TelephonyServer` is–as implied by the name–a server that is responsible for
receiving and making phone calls.
The server is built using FastAPI and utilizes Twilio for telephony services.

Clone the Vocode repo or copy the [Telephony app](https://github.com/vocodedev/vocode-python/tree/main/apps/telephony_app) directory.

## Running the server

Pick one of these two ways to run the server: 1. Run everything with Docker, 2. Run Python directly

### Option 1: Run everything With Docker

1. Build the telephony app Docker image. From the `telephony_app` directory, run:

```bash theme={null}
docker build -t vocode-telephony-app .
```

2. Run the application using `docker-compose`. From the `telephony_app` directory, run:

```bash theme={null}
docker-compose up
```

### Option 2: Run Python directly

Run the following steps from the `telephony_app` directory.

1. Install [Poetry](https://python-poetry.org/) and install dependencies.

```
poetry install
```

2. Run Redis with the default port of 6379.

For example, using Homebrew:

```
brew services start redis
```

Or if you prefer to use Docker for this part:

```
docker run -dp 6379:6379 -it redis/redis-stack:latest
```

3. Run the server with `uvicorn` (should be already installed in step 1).

```
poetry run uvicorn main:app --port 3000
```

## Setting up an inbound number

1. Create a [Twilio](https://www.twilio.com/) account
2. Once inside your dashboard, go to Phone Numbers -> Manage -> Buy a number to get a phone number.
3. Then, go to Phone Numbers -> Manage -> Active Numbers and select the number you want to set up.
4. Update the config to point the Webhook URL to `https://<YOUR BASE URL>/inbound_call` - if you're using `ngrok`, it looks like `https://asdf1234.ngrok.app/inbound_call`

<img src="https://mintcdn.com/vocode/rxa1NXWWEO6oPprO/images/twilio_number_config.png?fit=max&auto=format&n=rxa1NXWWEO6oPprO&q=85&s=9f60e978b45a0a335c2d5a952862255a" alt="Setup" width="827" height="446" data-path="images/twilio_number_config.png" />

5. Hit **Save** and call the number!

## Executing outbound calls

Make sure the server we just set up is already running. Then, in `outbound_call.py`

Replace the `to_phone` with the number you want to call and the `from_phone` with the number you want to call from. In order to make a call from the `from_phone`, you must have access to it via Twilio (either a number purchased via Twilio or verify the caller ID).

Run the script with `poetry run python outbound_call.py`.

## Configuration

Both the `OutboundCall` (in `outbound_call.py`) and `InboundCallConfig` (in `telephony_app.py`) classes can accept a `TranscriberConfig`, `AgentConfig`
or `SynthesizerConfig` - the default transcriber is Deepgram and the default synthesizer is Azure.

This example sets up an agent that spells every word that is sent to it - any text-in, text-out function can be turned into a voice conversation by subclassing `BaseAgent` and creating an `AgentFactory`.

```
import typing
from typing import Optional, Tuple

from vocode.streaming.agent.abstract_factory import AbstractAgentFactory
from vocode.streaming.agent.base_agent import BaseAgent, RespondAgent
from vocode.streaming.agent.chat_gpt_agent import ChatGPTAgent
from vocode.streaming.models.agent import AgentConfig, AgentType, ChatGPTAgentConfig


class SpellerAgentConfig(AgentConfig, type="agent_speller"):
    pass


class SpellerAgent(RespondAgent[SpellerAgentConfig]):
    async def respond(
        self,
        human_input: str,
        conversation_id: str,
        is_interrupt: bool = False,
    ) -> Tuple[Optional[str], bool]:
        return "".join(c + " " for c in human_input), False


class SpellerAgentFactory(AbstractAgentFactory):
    def create_agent(self, agent_config: AgentConfig) -> BaseAgent:
        # If the agent configuration type is CHAT_GPT, create a ChatGPTAgent.
        if isinstance(agent_config, ChatGPTAgentConfig):
            return ChatGPTAgent(agent_config=agent_config)
        # If the agent configuration type is agent_speller, create a SpellerAgent.
        elif isinstance(agent_config, SpellerAgentConfig):
            return SpellerAgent(agent_config=agent_config)
        # If the agent configuration type is not recognized, raise an exception.
        raise Exception("Invalid agent config")
```

An `AgentFactory` instance is passed into the `TelephonyServer` in `telephony_app.py`.

We provide a small set of agents with already created `AgentConfig`s, including, importantly, one that sets up ChatGPT with a configured prompt: see our `Python Quickstart` for more info.

### Accessing call information in your agent

We store the `to` and `from` numbers in the [`ConfigManager`](https://github.com/vocodedev/vocode-core/blob/53b01dab0b59f71961ee83dbcaf3653a6935c2e3/apps/telephony_app/main.py#L30) - so
if you'd like to access them in your agent, you can instantiate the manager to hook into the same Redis instance:

```
class SpellerAgent(BaseAgent):
    def __init__(self, agent_config: SpellerAgentConfig):
        super().__init__(agent_config=agent_config)
        self.config_manager = RedisConfigManager()

    async def respond(
        self,
        human_input: str,
        conversation_id: str,
        is_interrupt: bool = False,
    ) -> Tuple[Optional[str], bool]:
        call_config = self.config_manager.get_config(conversation_id)
        if call_config is not None:
            from_phone = call_config.twilio_from
            to_phone = call_config.twilio_to
        return "".join(c + " " for c in human_input), False
```
