Skip to content

Commit ad14948

Browse files
priyanshi-2003swaroopvarma1
authored andcommitted
adding support for the external call via proxy
1 parent 3fedd89 commit ad14948

13 files changed

Lines changed: 136 additions & 24 deletions

File tree

.env.example

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@ AUTOMATIC_OPENAI_STT_PROMPT="Transcribe Indian languages accurately. Recognize a
108108
AUTOMATIC_WRITE_ACTIONS_AUTHORIZED_USERS=user1@mail.com,user2@mail.com,...
109109
AUTOMATIC_ACTIONS_REQUIRE_AUTH=create_euler_offer,delete_euler_offer,...
110110

111+
# Proxy Configuration
112+
AWS_PROXY_HOST=localhost
113+
AWS_PROXY_PORT=80
114+
CLOUD_PROVIDER=AWS
115+
111116
# LangFuse Configuration
112117
ENABLE_LANGFUSE_PROMPTS=false
113118
LANGFUSE_SECRET_KEY=''

app/agents/voice/automatic/services/mcp/automatic_client.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from app.core.config import MCP_CLIENT_TIMEOUT
99
from app.core.logger import logger
10+
from app.core.transport.http_client import create_http_client
1011
from pipecat.adapters.schemas.tools_schema import ToolsSchema
1112
from pipecat.adapters.schemas.function_schema import FunctionSchema
1213
from app.agents.voice.automatic.types.models import (
@@ -33,7 +34,7 @@ def __init__(self, server_url: str, auth_token: str, context: Dict[str, Any]):
3334
self._server_url = server_url.strip()
3435
self._auth_token = auth_token
3536
self._context_b64 = base64.b64encode(json.dumps(context).encode()).decode()
36-
self._client = httpx.AsyncClient(timeout=MCP_CLIENT_TIMEOUT)
37+
self._client = create_http_client(timeout=MCP_CLIENT_TIMEOUT)
3738
self._demo_mode = context.get("enableDemoMode", False)
3839

3940
async def post(

app/agents/voice/automatic/tools/breeze/analytics.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from pipecat.services.llm_service import FunctionCallParams
1010
from pipecat.adapters.schemas.function_schema import FunctionSchema
1111
from pipecat.adapters.schemas.tools_schema import ToolsSchema
12+
from app.core.transport.http_client import create_http_client
1213

1314
# These will be set by the initializer
1415
breeze_token: str | None = None
@@ -98,7 +99,7 @@ async def _make_breeze_request(params: FunctionCallParams, operational_tab: str)
9899
)
99100

100101
try:
101-
async with httpx.AsyncClient(timeout=30.0) as client:
102+
async with create_http_client(timeout=30.0) as client:
102103
response = await client.post(api_url, json=payload, headers=headers)
103104
response.raise_for_status() # Raise an exception for bad status codes
104105
response_json = response.json()
@@ -223,7 +224,7 @@ async def get_breeze_marketing_data(params: FunctionCallParams):
223224
logger.info(f"Requesting Breeze marketing data with payload: {json.dumps(payload)}")
224225

225226
try:
226-
async with httpx.AsyncClient() as client:
227+
async with create_http_client() as client:
227228
response = await client.post(api_url, json=payload, headers=headers)
228229
response.raise_for_status()
229230
response_json = response.json()
@@ -326,7 +327,7 @@ async def get_breeze_address_data(params: FunctionCallParams):
326327
logger.info(f"Requesting Breeze address data with payload: {json.dumps(payload)}")
327328

328329
try:
329-
async with httpx.AsyncClient() as client:
330+
async with create_http_client() as client:
330331
response = await client.post(api_url, json=payload, headers=headers)
331332
response.raise_for_status()
332333
response_json = response.json()

app/agents/voice/automatic/tools/breeze/utils.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
from app.core.logger import logger
1515
from app.core.config import LIGHTHOUSE_APP_URL
16+
from app.core.transport.http_client import create_http_client
1617

1718

1819
def safe_construct_url(url: str) -> Optional[urlparse]:
@@ -115,7 +116,7 @@ async def get_current_shop_config_data(shop_url: str) -> Dict[str, Any]:
115116

116117
try:
117118
logger.info(f"Fetching shop config from: {url}")
118-
async with httpx.AsyncClient(timeout=30.0) as client:
119+
async with create_http_client(timeout=30.0) as client:
119120
response = await client.get(url)
120121
response.raise_for_status()
121122
config_data = response.json()
@@ -165,7 +166,7 @@ async def patch_shop_config(
165166
"x-auth-token": breeze_token,
166167
}
167168
try:
168-
async with httpx.AsyncClient(timeout=timeout) as client:
169+
async with create_http_client(timeout=timeout) as client:
169170
response = await client.patch(url, headers=headers, json=config_data)
170171
response.raise_for_status()
171172
return response.json()

app/agents/voice/automatic/tools/juspay/analytics.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
ApiSuccess,
1515
GeniusApiResponse,
1616
)
17+
from app.core.transport.http_client import create_http_client
1718

1819
# This token will be set when the tools are initialized
1920
euler_token: str | None = None
@@ -115,7 +116,7 @@ async def _make_genius_api_request(
115116
)
116117

117118
try:
118-
async with httpx.AsyncClient(timeout=10.0) as client:
119+
async with create_http_client(timeout=10.0) as client:
119120
response = await client.post(
120121
GENIUS_API_URL, json=full_payload, headers=headers
121122
)
@@ -344,7 +345,7 @@ async def list_offers_by_filter(params: FunctionCallParams):
344345
f"Requesting Euler offers list from: {endpoint} | Payload: {json.dumps(payload, indent=2)}"
345346
)
346347

347-
async with httpx.AsyncClient(timeout=30.0) as client:
348+
async with create_http_client(timeout=30.0) as client:
348349
response = await client.post(endpoint, json=payload, headers=headers)
349350

350351
if response.status_code != 200:
@@ -736,7 +737,7 @@ async def create_euler_offer(params: FunctionCallParams):
736737
f"Making offer creation request to: {endpoint} | Payload: {json.dumps(api_payload, indent=2)}"
737738
)
738739

739-
async with httpx.AsyncClient(timeout=10.0) as client:
740+
async with create_http_client(timeout=10.0) as client:
740741
response = await client.post(endpoint, json=api_payload, headers=headers)
741742

742743
if response.status_code == 200:
@@ -890,7 +891,7 @@ async def find_offer_by_code(offer_code: str) -> dict | None:
890891
f"Searching for offer with code '{offer_code}' using endpoint: {endpoint}"
891892
)
892893

893-
async with httpx.AsyncClient(timeout=30.0) as client:
894+
async with create_http_client(timeout=30.0) as client:
894895
response = await client.post(endpoint, json=search_payload, headers=headers)
895896

896897
if response.status_code == 200:
@@ -983,7 +984,7 @@ async def delete_euler_offer(params: FunctionCallParams):
983984
f"Deleting offer with ID '{offer_id}' using endpoint: {delete_endpoint}"
984985
)
985986

986-
async with httpx.AsyncClient(timeout=30.0) as client:
987+
async with create_http_client(timeout=30.0) as client:
987988
response = await client.post(
988989
delete_endpoint, json=delete_payload, headers=headers
989990
)
@@ -1194,7 +1195,7 @@ async def update_euler_offer(params: FunctionCallParams):
11941195

11951196
logger.info(f"Using status-only endpoint: {status_endpoint}")
11961197

1197-
async with httpx.AsyncClient(timeout=30.0) as client:
1198+
async with create_http_client(timeout=30.0) as client:
11981199
response = await client.post(
11991200
status_endpoint, json=status_payload, headers=headers
12001201
)
@@ -1544,7 +1545,7 @@ async def update_euler_offer(params: FunctionCallParams):
15441545
)
15451546
logger.info(f"Payload: {json.dumps(api_payload, indent=2)}")
15461547

1547-
async with httpx.AsyncClient(timeout=30.0) as client:
1548+
async with create_http_client(timeout=30.0) as client:
15481549
response = await client.put(
15491550
update_endpoint, json=api_payload, headers=headers
15501551
)

app/agents/voice/breeze_buddy/managers/calls.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from datetime import datetime, timezone, timedelta
66
from app.core.logger import logger
77
import uuid
8-
import aiohttp
8+
from app.core.transport.http_client import create_aiohttp_session
99
from app.database.accessor import (
1010
get_leads_based_on_status_and_next_attempt,
1111
get_call_execution_config_by_merchant_id,
@@ -33,7 +33,7 @@ async def process_backlog_leads():
3333
Processes backlog leads and initiates calls.
3434
"""
3535
logger.info("Processing backlog leads...")
36-
async with aiohttp.ClientSession() as session:
36+
async with create_aiohttp_session() as session:
3737
try:
3838
leads = await get_leads_based_on_status_and_next_attempt(
3939
LeadCallStatus.BACKLOG, datetime.now(timezone.utc)

app/agents/voice/breeze_buddy/services/telephony/exotel/exotel.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import requests
44

55
from app.core.logger import logger
6+
from app.core.transport.http_client import create_aiohttp_session
67

78
from pipecat.serializers.exotel import ExotelFrameSerializer
89

@@ -52,7 +53,11 @@ def make_call(self, customer_mobile_number: str, outbound_number: str):
5253
logger.info(f"Payload: {payload}")
5354

5455
try:
55-
resp = requests.post(url, data=payload)
56+
# Use centralized proxy configuration
57+
proxy_url = get_proxy_config()
58+
proxies = {"https": proxy_url, "http": proxy_url} if proxy_url else None
59+
60+
resp = requests.post(url, data=payload, proxies=proxies)
5661
logger.info(f"Exotel API response status: {resp.status_code}")
5762
logger.info(f"Exotel API response headers: {dict(resp.headers)}")
5863
logger.info(f"Exotel API response content: {resp.text}")

app/agents/voice/breeze_buddy/services/telephony/twilio/twilio.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
from fastapi import WebSocket, HTTPException
22
from twilio.rest import Client
3+
from twilio.http.http_client import TwilioHttpClient
34
from twilio.twiml.voice_response import VoiceResponse, Connect, Stream
45

56
from app.agents.voice.breeze_buddy.services.telephony.base_provider import (
67
VoiceCallProvider,
78
)
89
from app.core import config
10+
from app.core.transport.http_client import create_aiohttp_session
911
from app.agents.voice.breeze_buddy.workflows.order_confirmation.websocket_bot import (
1012
main as telephony_websocket_conn,
1113
)
@@ -22,9 +24,29 @@ async def _hang_up_call(self):
2224

2325
def __init__(self, aiohttp_session):
2426
super().__init__(config, aiohttp_session)
25-
self.client = Client(
26-
self.config.TWILIO_ACCOUNT_SID, self.config.TWILIO_AUTH_TOKEN
27-
)
27+
28+
# Create Twilio client with proper proxy configuration
29+
self.client = self._create_twilio_client()
30+
31+
def _create_twilio_client(self) -> Client:
32+
"""Create Twilio client with proper proxy configuration using TwilioHttpClient"""
33+
proxy_url = get_proxy_config()
34+
account_sid = self.config.TWILIO_ACCOUNT_SID
35+
auth_token = self.config.TWILIO_AUTH_TOKEN
36+
37+
if proxy_url:
38+
logger.info(f"Configuring Twilio client with proxy: {proxy_url}")
39+
# Use TwilioHttpClient with proxy configuration
40+
proxy_client = TwilioHttpClient(
41+
proxy={
42+
"http": proxy_url,
43+
"https": proxy_url,
44+
}
45+
)
46+
return Client(account_sid, auth_token, http_client=proxy_client)
47+
else:
48+
logger.info("Creating Twilio client without proxy")
49+
return Client(account_sid, auth_token)
2850

2951
def hangup_call(self, call_sid: str):
3052
self.client.calls(call_sid).update(status="completed")

app/api/routers/breeze_buddy.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from app.agents.voice.breeze_buddy.workflows.order_confirmation.types import (
2424
BreezeOrderData,
2525
)
26-
import aiohttp
26+
from app.core.transport.http_client import create_aiohttp_session
2727
from app.agents.voice.breeze_buddy.managers.calls import (
2828
process_backlog_leads,
2929
handle_call_completion,
@@ -286,7 +286,7 @@ async def telephony_websocket_handler(
286286

287287
logger.info(f"Handling websocket for {workflow}")
288288

289-
async with aiohttp.ClientSession() as session:
289+
async with create_aiohttp_session() as session:
290290
try:
291291
provider = get_voice_provider(service_provider.upper(), session)
292292
provider.set_completion_callback(handle_call_completion)

app/core/config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,10 @@ def get_required_env(var_name: str) -> str:
281281
EXOTEL_SUBDOMAIN = os.getenv("EXOTEL_SUBDOMAIN", "api.exotel.com")
282282
EXOTEL_APPLET_APP_ID = os.getenv("EXOTEL_APPLET_APP_ID", "1044183")
283283

284+
# Proxy Configuration
285+
AWS_PROXY_HOST = os.environ.get("AWS_PROXY_HOST")
286+
AWS_PROXY_PORT = os.environ.get("AWS_PROXY_PORT")
287+
CLOUD_ENVIRONMENT = os.environ.get("CLOUD_ENVIRONMENT", "GCP") # AWS, GCP, AZURE, etc.
284288

285289
# LangFuse Configuration
286290
ENABLE_LANGFUSE_PROMPTS = (

0 commit comments

Comments
 (0)