142 lines
4.9 KiB
Python
142 lines
4.9 KiB
Python
import logging
|
|
from typing import Optional
|
|
from fastapi import APIRouter, Form, Response
|
|
from pydantic import BaseModel
|
|
from vocode.streaming.agent.base_agent import BaseAgent
|
|
from vocode.streaming.models.agent import AgentConfig
|
|
from vocode.streaming.models.synthesizer import (
|
|
AzureSynthesizerConfig,
|
|
SynthesizerConfig,
|
|
)
|
|
from vocode.streaming.models.transcriber import (
|
|
DeepgramTranscriberConfig,
|
|
PunctuationEndpointingConfig,
|
|
TranscriberConfig,
|
|
)
|
|
from vocode.streaming.synthesizer.base_synthesizer import BaseSynthesizer
|
|
from vocode.streaming.telephony.config_manager.base_config_manager import (
|
|
BaseConfigManager,
|
|
)
|
|
from vocode.streaming.telephony.constants import (
|
|
DEFAULT_AUDIO_ENCODING,
|
|
DEFAULT_CHUNK_SIZE,
|
|
DEFAULT_SAMPLING_RATE,
|
|
)
|
|
|
|
from vocode.streaming.telephony.server.router.calls import CallsRouter
|
|
from vocode.streaming.telephony.server.router.twiml import TwiMLRouter
|
|
from vocode.streaming.models.telephony import (
|
|
CallConfig,
|
|
CallEntity,
|
|
CreateOutboundCall,
|
|
CreateInboundCall,
|
|
DialIntoZoomCall,
|
|
EndOutboundCall,
|
|
TwilioConfig,
|
|
)
|
|
|
|
from vocode.streaming.telephony.conversation.call import Call
|
|
from vocode.streaming.telephony.templates import Templater
|
|
from vocode.streaming.transcriber.base_transcriber import BaseTranscriber
|
|
from vocode.streaming.utils import create_conversation_id
|
|
|
|
|
|
class InboundCallConfig(BaseModel):
|
|
url: str
|
|
agent_config: AgentConfig
|
|
twilio_config: Optional[TwilioConfig] = None
|
|
transcriber_config: Optional[TranscriberConfig] = None
|
|
synthesizer_config: Optional[SynthesizerConfig] = None
|
|
|
|
|
|
class TelephonyServer:
|
|
def __init__(
|
|
self,
|
|
base_url: str,
|
|
config_manager: BaseConfigManager,
|
|
inbound_call_configs: list[InboundCallConfig] = [],
|
|
logger: Optional[logging.Logger] = None,
|
|
):
|
|
self.base_url = base_url
|
|
self.logger = logger or logging.getLogger(__name__)
|
|
self.router = APIRouter()
|
|
self.config_manager = config_manager
|
|
self.templater = Templater()
|
|
self.router.include_router(
|
|
CallsRouter(
|
|
base_url=base_url,
|
|
templater=self.templater,
|
|
config_manager=self.config_manager,
|
|
logger=self.logger,
|
|
).get_router()
|
|
)
|
|
self.router.include_router(
|
|
TwiMLRouter(
|
|
base_url=base_url, templater=self.templater, logger=self.logger
|
|
).get_router()
|
|
)
|
|
for config in inbound_call_configs:
|
|
self.router.add_api_route(
|
|
config.url,
|
|
self.create_inbound_route(
|
|
agent_config=config.agent_config,
|
|
twilio_config=config.twilio_config,
|
|
transcriber_config=config.transcriber_config,
|
|
synthesizer_config=config.synthesizer_config,
|
|
),
|
|
methods=["POST"],
|
|
)
|
|
logger.info(f"Set up inbound call TwiML at https://{base_url}{config.url}")
|
|
|
|
def create_inbound_route(
|
|
self,
|
|
agent_config: AgentConfig,
|
|
twilio_config: Optional[TwilioConfig] = None,
|
|
transcriber_config: Optional[TranscriberConfig] = None,
|
|
synthesizer_config: Optional[SynthesizerConfig] = None,
|
|
):
|
|
def route(twilio_sid: str = Form(alias="CallSid")) -> Response:
|
|
call_config = CallConfig(
|
|
transcriber_config=transcriber_config
|
|
or DeepgramTranscriberConfig(
|
|
sampling_rate=DEFAULT_SAMPLING_RATE,
|
|
audio_encoding=DEFAULT_AUDIO_ENCODING,
|
|
chunk_size=DEFAULT_CHUNK_SIZE,
|
|
model="voicemail",
|
|
endpointing_config=PunctuationEndpointingConfig(),
|
|
),
|
|
agent_config=agent_config,
|
|
synthesizer_config=synthesizer_config
|
|
or AzureSynthesizerConfig(
|
|
sampling_rate=DEFAULT_SAMPLING_RATE,
|
|
audio_encoding=DEFAULT_AUDIO_ENCODING,
|
|
),
|
|
twilio_config=twilio_config,
|
|
twilio_sid=twilio_sid,
|
|
)
|
|
|
|
conversation_id = create_conversation_id()
|
|
self.config_manager.save_config(conversation_id, call_config)
|
|
return self.templater.get_connection_twiml(
|
|
base_url=self.base_url, call_id=conversation_id
|
|
)
|
|
|
|
return route
|
|
|
|
async def end_outbound_call(self, conversation_id: str):
|
|
# TODO validation via twilio_client
|
|
call_config = self.config_manager.get_config(conversation_id)
|
|
if not call_config:
|
|
raise ValueError("Call not found")
|
|
call = Call.from_call_config(
|
|
self.base_url,
|
|
call_config,
|
|
self.config_manager,
|
|
conversation_id,
|
|
self.logger,
|
|
)
|
|
call.end_twilio_call()
|
|
return {"id": call.id}
|
|
|
|
def get_router(self) -> APIRouter:
|
|
return self.router
|