Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion llmstack/apps/apis.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from django.core.validators import validate_email
from django.db.models import Q
from django.forms import ValidationError
from django.http import HttpResponse, StreamingHttpResponse
from django.http import StreamingHttpResponse
from django.shortcuts import get_object_or_404
from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_page
Expand Down
1 change: 1 addition & 0 deletions llmstack/apps/app_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from .types.web import WebApp
from .types.discord import DiscordApp
from .types.slack import SlackApp
from .types.twilio_sms import TwilioSmsApp


class AppTypeFactory:
Expand Down
5 changes: 3 additions & 2 deletions llmstack/apps/integration_configs.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,12 @@ class DiscordIntegrationConfig(AppIntegrationConfig):
bot_token: str = ''
public_key: str = ''
slash_command_id: Optional[str] = None



class TwilioIntegrationConfig(AppIntegrationConfig):
config_type = 'twilio'
is_encrypted = True
account_sid: str = ''
auth_token: str = ''
phone_numbers: list = []

auto_create_sms_webhook = False
7 changes: 6 additions & 1 deletion llmstack/apps/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

logger = logging.getLogger(__name__)


class AppVisibility(models.IntegerChoices):
PRIVATE = 0, 'Private' # only the owner of the app and listed emails can access the app
# only members of the organization can access the app
Expand Down Expand Up @@ -237,7 +238,7 @@ def slack_config(self):
def discord_config(self):
profile = Profile.objects.get(user=self.owner)
return DiscordIntegrationConfig().from_dict(self.discord_integration_config, profile.decrypt_value) if self.discord_integration_config else None

@property
def twilio_config(self):
profile = Profile.objects.get(user=self.owner)
Expand Down Expand Up @@ -408,3 +409,7 @@ def update_app_pre_save(sender, instance, **kwargs):
instance.type, 'slack',
)
instance = slack_app_type_handler_cls.pre_save(instance)

twilio_sms_type_handler_cls = AppTypeFactory.get_app_type_handler(
instance.type, 'twilio_sms')
instance = twilio_sms_type_handler_cls.pre_save(instance)
87 changes: 87 additions & 0 deletions llmstack/apps/types/twilio_sms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import logging
from typing import List

from pydantic import Field
import requests
from llmstack.apps.models import App
from llmstack.apps.types.app_type_interface import AppTypeInterface, BaseSchema

logger = logging.getLogger(__name__)


class TwilioSmsAppConfigSchema(BaseSchema):
account_sid: str = Field(
title='Account SID', description="Account SID of the Twilio account. Your account's SID can be found in the console.", required=True,
)
auth_token: str = Field(
title='Auth Token', widget='password',
description="Auth token of the Twilio account. Your account's auth token can be found in the console.", required=True,
)
phone_numbers: List[str] = Field(
title='Phone Numbers', description='Phone numbers to send SMS messages from.', required=True,
)
auto_create_sms_webhook: bool = Field(default=False, title='Auto Create SMS Webhook',
description='Automatically create an SMS webhook for the phone numbers.', required=False,
)


class TwilioSmsApp(AppTypeInterface[TwilioSmsAppConfigSchema]):
@staticmethod
def slug() -> str:
return 'twilio_sms'

@staticmethod
def name() -> str:
return 'Twilio SMS App'

@staticmethod
def description() -> str:
return 'Send SMS messages from Twilio.'

@classmethod
def pre_save(self, app: App):
if app.is_published and app.twilio_config:
config = app.twilio_config
phone_numbers = config.get('phone_numbers', [])

account_sid = config.get('account_sid', None)
auth_token = config.get('auth_token', None)
auto_create_sms_webhook = config.get(
'auto_create_sms_webhook', False)

if not phone_numbers:
raise Exception(
'You must provide at least one phone number to send SMS messages from.')
if not account_sid or not auth_token:
raise Exception(
'You must provide an account SID and auth token to send SMS messages from.')

headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json'
}
auth = (account_sid, auth_token)
for phone_number in phone_numbers:
ph_no = phone_number.strip().replace('+', '').replace('-', '')
response = requests.get(
f'https://api.twilio.com/2010-04-01/Accounts/{account_sid}/IncomingPhoneNumbers.json?PhoneNumber=%2B{ph_no}',
headers=headers, auth=auth)
if response.status_code != 200:
raise Exception(
f'Invalid phone number {phone_number}. Please provide a valid phone number that you own.')
twilio_phone_number_resource = response.json()[
'incoming_phone_numbers'][0]
sms_url = twilio_phone_number_resource['sms_url']
# Create SMS webhook if it doesn't exist
if auto_create_sms_webhook and (not sms_url or sms_url != f'https://trypromptly.com/api/apps/{app.uuid}/twiliosms/run'):
# Update twilio phone number resource with voice webhook
response = requests.post(
f'https://api.twilio.com/2010-04-01/Accounts/{account_sid}/IncomingPhoneNumbers/{twilio_phone_number_resource["sid"]}.json',
headers=headers, auth=auth, data={
'SmsUrl': f'https://trypromptly.com/api/apps/{app.uuid}/twiliosms/run',
})
if response.status_code != 200:
raise Exception(
f'Failed to update SMS webhook for phone number {phone_number}. Error: {response.text}')

return app
6 changes: 6 additions & 0 deletions llmstack/client/src/components/apps/AppTwilioConfigEditor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ const twilioConfigSchema = {
type: "string",
},
},
auto_create_sms_webhook: {
type: "boolean",
title: "Create Twilio SMS Webhook",
description:
"Update Twilio SMS Webhook to point to send message to application",
},
},
};

Expand Down