This content originally appeared on Twilio Blog and was authored by Niels Swimberghe
ChatGPT is a state-of-the-art natural language processing tool by OpenAI that can help you create a chatbot that can provide accurate and helpful responses to user queries.
With its extensive knowledge base and advanced language processing capabilities, ChatGPT can assist you in developing a chatbot that delivers a seamless and engaging user experience. It's worth noting that this introduction was generated using ChatGPT itself, with some minor editing, showcasing the power and versatility of this language model.
OpenAI has opened up an API for ChatGPT, but in addition to that, Microsoft Azure has been working with OpenAI to offer its own version of OpenAI's models through Azure, adding on the security, integration, and management features you expect from the Azure cloud platform.
The interesting thing about Azure OpenAI Service, is that the same models are used by OpenAI, but they are deployed inside your Azure subscription. This means they are completely isolated from OpenAI and from other Azure OpenAI Services so you don't have to worry about accidentally sharing data with others.
While Azure has released the Azure OpenAI Service as "Generally Available", you’ll still need to fill out this form and be approved by Microsoft to get access to the service. (C'mon Microsoft, any service where you have to be manually approved is not GA, but I digress.)
In this tutorial, you'll learn how to create an Azure OpenAI Service and consume the API using the OpenAI .NET client library to create a chatbot inside the console.
In this tutorial, you'll learn how to
- integrate Twilio SMS with ASP.NET Core,
- create an Azure OpenAI instance and model deployment,
- and call the chat completions API using the Azure OpenAI client library to create the chatbot.
Let's get started!
Prerequisites
Here’s what you will need to follow along:
- .NET 7 SDK (earlier and newer versions may work too)
- A code editor or IDE (I recommend JetBrains Rider, Visual Studio, or VS Code with the C# plugin)
- An Azure Subscription and access to Azure OpenAI Service (request access here)
- A free Twilio account (sign up with Twilio for free)
- A Twilio phone number
- The ngrok CLI and, optionally, a free ngrok account
You can find the source code for this tutorial on GitHub. Use it if you run into any issues, or submit an issue if you run into problems.
Create and set up a Twilio SMS project
Open a shell, use the .NET CLI to create an empty web project named AzChatGptSms, and change into the project directory, using these commands:
dotnet new web -n AzChatGptSms
cd AzChatGptSms
The Twilio .NET SDK lets you communicate with Twilio's APIs without having to manually write the HTTP code. Add the Twilio .NET SDK using the following command:
dotnet add package Twilio
The Twilio helper library for ASP.NET Core helps you integrate Twilio into ASP.NET Core. Add the helper library for ASP.NET Core using the following command:
dotnet add package Twilio.AspNet.Core
Open the project in your preferred .NET IDE and update the Program.cs file to match the following code:
using Twilio.AspNet.Core;
using AzChatGptSms;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession(options =>
{
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
});
builder.Services.AddTwilioClient();
var app = builder.Build();
app.UseSession();
app.MapMessageEndpoint();
app.Run();
Here's an overview of the changes:
- The application configures server sessions to store the session data in memory. These sessions will be used to store the chat messages.
- The Twilio API client is registered as a service in the ASP.NET Core Dependency Injection (DI) container. Now the
ITwilioRestClient
andTwilioRestClient
can be injected into constructors and methods supported by DI.
MapMessageEndpoint
is an extension method that doesn't exist yet. Create a new file within your project directory named MessageEndpoint.cs and add the following code to it:
using Twilio.Clients;
using Twilio.Rest.Api.V2010.Account;
namespace AzChatGptSms;
public static class MessageEndpoint
{
public static IEndpointRouteBuilder MapMessageEndpoint(this IEndpointRouteBuilder builder)
{
builder.MapPost("/message", OnMessage);
return builder;
}
private static async Task<IResult> OnMessage(
HttpContext context,
ITwilioRestClient twilioClient,
CancellationToken cancellationToken
)
{
var request = context.Request;
var form = await request.ReadFormAsync(cancellationToken);
var receivedFrom = form["From"].ToString();
var sentTo = form["To"].ToString();
var body = form["Body"].ToString().Trim();
await MessageResource.CreateAsync(
to: receivedFrom,
from: sentTo,
body: $"You said: {body}",
client: twilioClient
);
return Results.Ok();
}
}
The MessageEndpoint.MapMessageEndpoint
extension method maps the /message endpoint for HTTP POST requests to the OnMessage
method.
Later, you will configure Twilio's message webhook to send HTTP POST requests to the /message endpoint. Twilio will send data about the incoming message as a form.
The OnMessage
method reads the form data from the request and extracts data from the form. The From
parameter is the phone number that sent the message. The To
parameter is the phone number that received the message, which will be your Twilio phone number. The Body
parameter is the content of the message itself. The MessageResource.CreateAsync
method sends a message back to the sender, repeating what the sender said.
Alternatively, you can use TwiML to respond to the incoming message. This is simpler and sufficient for most use cases, however, this application will require sending multiple messages in correct order, which you'll need to call the Twilio API for.
You'll need to configure the Twilio Account SID and Auth Token before you can communicate with the Twilio API using the Twilio REST client. Since the Auth Token is a secret that you should not share, you should avoid hard-coding it such as putting it in your appsettings.json file — or any other way that it could end up in your source control history. Instead, use the Secrets Manager aka user-secrets, environment variables, or a vault service.
Run the following commands to initialize user-secrets:
dotnet user-secrets init
Then, grab the Account SID and Auth Token from the Account Info panel of the Twilio Console and configure them using the following command, replacing [YOUR_ACCOUNT_SID]
with your Account SID and [YOUR_AUTH_TOKEN]
with your Auth Token:
dotnet user-secrets set Twilio:Client:AccountSid [YOUR_ACCOUNT_SID]
dotnet user-secrets set Twilio:Client:AuthToken [YOUR_AUTH_TOKEN]
Now, run your application using the following command:
dotnet run
In the application's output, you'll see a line similar to Now listening on: http://localhost:5209
. Copy the HTTP URL and port, as you'll need it shortly.
You can also create a Twilio API key to authenticate to Twilio's APIs instead of an Auth Token. API keys are easier to manage, and you can create one for each application as needed.
Configure the message webhook on your Twilio phone number
Next, you'll need to configure the message webhook on your Twilio phone number. Before you can do that, you'll need to make your locally running application accessible to the internet. You can quickly do this using ngrok which creates a secure tunnel to the internet for you.
Leave your .NET application running, and run the following command in a separate shell, after replacing [YOUR_LOCALHOST_URL]
with the URL and port which you copied previously:
ngrok http [YOUR_LOCALHOST_URL]
ngrok printed the Forwarding URL to the output, which you'll need to publicly access your local application. Copy it, as you'll need it in just a moment.
If you're using an HTTPS localhost URL, you'll first need a ngrok account, and authenticate the ngrok CLI.
Now, go back to the Twilio Console in your browser, and use the left navigation to navigate to Phone Numbers > Manage > Active Numbers. Then, click the Twilio phone number you want to test with. On the phone number configuration page, locate "A MESSAGE COMES IN" in the Messaging section. Underneath that, set the first dropdown to Webhook. Set the value of the text box next to the dropdown to the ngrok Forwarding URL which you just copied, and add /message at the end of the URL. Then click Save.
Now, text something to your Twilio phone number. You should receive an SMS back saying something like "You said: [whatever you said]".
Great job! You have an application that can receive SMS and send back SMS.
Your webhook endpoint has to be publicly accessible, so Twilio can send HTTP requests to them, but this means others can also send HTTP requests to your endpoint. You should add Twilio's request validation to your application to validate that the HTTP requests originated from Twilio, and not a malicious actor.
Create an Azure OpenAI instance
To create an Azure OpenAI Service, open a browser and navigate to the Azure Portal. Open the navigation on the left and click on Create a resource.
This will open the Azure Marketplace. Use the search box to search for "OpenAI" and click on the Azure OpenAI product.
On the product page for Azure OpenAI, click on the Create button.
Select the resource group you want to use, or create a new one, give your OpenAI instance a globally unique name, and select any pricing tier (there's only one at the time of writing this). Then click Next.
Leave the defaults on the Network and Tags page. Click Next until you reach the Review + submit page. Here you'll see an overview of what you're about to create. Click the Create button.
Now, Azure will provision your Azure OpenAI instance, which will take some time. It took about 10 minutes for me, so go make some coffee, or even better, some delicious tea. 😉
Once Azure says, "Your deployment is complete", click on the Go to resource button. Then in your OpenAI instance, click on the Model deployments tab in the left navigation, and then click the Create button up top.
Give your model any name, select gpt-35-turbo (version 0301) as the Model, select 0301 as the name, and click Save.
Gpt-35-turbo is the model that OpenAI trained specifically for ChatGPT, however, ChatGPT also offers a newer model GPT-4 which is not yet available in Azure OpenAI.
You can't customize your model inside the Azure portal itself, but there's a link that says "Go to Azure OpenAI Studio" which takes you to the Cognitive Services portal where you can use the playground to experiment with the different models, and you can customize the model by providing extra training data. Keep in mind, this is just the start of this new service, and there's a lot more to come ;)
Remember the name of your Model deployment, as you'll need this later in your .NET application.
Now, click on the Keys and Endpoint tab in the left navigation and copy the KEY 1 and Endpoint somewhere safe. You'll need these two for your .NET application as well.
Communicate with Azure OpenAI
Azure provides their own client library or SDK to communicate with the Azure OpenAI service. To use the library, add the Azure OpenAI NuGet package using the .NET CLI:
dotnet add package Azure.AI.OpenAI --prerelease
The SDK is only available as a prerelease at the moment, as it's still in beta. If a normal release is available, feel free to drop the prerelease-argument.
To add the OpenAI client to ASP.NET Core's DI container, you'll also need to add the Microsoft.Extensions.Azure NuGet package:
dotnet add package Microsoft.Extensions.Azure
Add the following namespaces to the top of the Program.cs file:
using Azure;
using Microsoft.Extensions.Azure;
And add the OpenAI client to the DI container by adding the highlighted lines to Program.cs:
builder.Services.AddTwilioClient();
builder.Services.AddAzureClients(clientBuilder =>
{
clientBuilder.AddOpenAIClient(
new Uri(builder.Configuration["Azure:OpenAI:Endpoint"]),
new AzureKeyCredential(builder.Configuration["Azure:OpenAI:ApiKey"])
);
});
var app = builder.Build();
Next, configure all the Azure OpenAI configuration as user-secrets, replacing [YOUR_AZURE_OPENAI_ENDPOINT]
with the ENDPOINT URL, [YOUR_AZURE_OPENAI_APIKEY]
with the KEY 1, and [YOUR_MODEL_DEPLOYMENT]
with the name of the Model Deployment you took note of earlier.
dotnet user-secrets set Azure:OpenAI:Endpoint [YOUR_AZURE_OPENAI_ENDPOINT]
dotnet user-secrets set Azure:OpenAI:ApiKey [YOUR_AZURE_OPENAI_APIKEY]
dotnet user-secrets set Azure:OpenAI:ModelName [YOUR_MODEL_DEPLOYMENT]
Next, update MessageEndpoint.cs with the following code:
using System.Security.Cryptography;
using System.Text;
using Azure.AI.OpenAI;
using Twilio.Clients;
using Twilio.Rest.Api.V2010.Account;
namespace AzChatGptSms;
public static class MessageEndpoint
{
public static IEndpointRouteBuilder MapMessageEndpoint(this IEndpointRouteBuilder builder)
{
builder.MapPost("/message", OnMessage);
return builder;
}
private static async Task<IResult> OnMessage(
HttpContext context,
OpenAIClient openAiClient,
ITwilioRestClient twilioClient,
IConfiguration configuration,
CancellationToken cancellationToken
)
{
var request = context.Request;
var form = await request.ReadFormAsync(cancellationToken).ConfigureAwait(false);
var receivedFrom = form["From"].ToString();
var sentTo = form["To"].ToString();
var body = form["Body"].ToString().Trim();
// ChatGPT doesn't need the phone number, just any string that uniquely identifies the user,
// hence I'm hashing the phone number to not pass in PII unnecessarily
var userId = Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(receivedFrom)));
var chatCompletionOptions = new ChatCompletionsOptions
{
User = userId,
Messages = {new ChatMessage(ChatRole.User, body)}
};
var chatCompletionsResponse = await openAiClient.GetChatCompletionsAsync(
configuration["Azure:OpenAI:ModelName"],
chatCompletionOptions,
cancellationToken
);
var chatResponse = chatCompletionsResponse.Value.Choices[0].Message.Content;
await MessageResource.CreateAsync(
to: receivedFrom,
from: sentTo,
body: chatResponse,
client: twilioClient
);
return Results.Ok();
}
}
The OpenAIClient
is injected into the openAiClient
parameter of the OnMessage
method.
User
is one of the optional parameters you can pass to the ChatGPT API. While it is optional, it helps ChatGPT monitor and detect abuse, so I recommend passing it in. The only data you have access to that uniquely identifies the current use is their phone number. Since a phone number is Personally Identifiable Information (PII), I decided not to hand that to OpenAI, but instead to hash it first using the SHA256 hashing algorithm.
Next, the endpoint will pass the SMS body to the chat completions API and retrieve the response. The response is then sent back to the sender using Twilio.
The chat completions API has a lot more options than used in this tutorial. I recommend reading up on the chat API reference to customize your chatbot to your needs.
Run your application again using the following command:
dotnet run
Then, ask your chatbot anything by texting a question to your Twilio phone number.
It is possible that the response from ChatGPT is too large and will cause an error or deliverability issues. You'll fix this issue soon, but for now, try asking something simpler.
I asked the chatbot for a joke about dogs, and it delivered a great joke, however, when I asked it for a follow-up joke about cats, without explicitly mentioning a joke, it just gave me information about cats.
This is because the chat completions API does not maintain the context of the previous messages by default. Let's fix that.
Persist chat history as context
Since the chat completions API doesn't persist the history of the chat, it is not able to use the history as context to generate new responses. To solve this problem, you have to persist the history in your application, and pass the entire chat history to the chat completions API, for every new query.
In this tutorial, you'll store the history of the chat in ASP.NET Core's server session. Update the MessageEndpoint.cs like this:
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using Azure.AI.OpenAI;
using Twilio.Clients;
using Twilio.Rest.Api.V2010.Account;
namespace AzChatGptSms;
public static class MessageEndpoint
{
private const string PreviousMessagesKey = "PreviousMessages";
public static IEndpointRouteBuilder MapMessageEndpoint(this IEndpointRouteBuilder builder)
{
builder.MapPost("/message", OnMessage);
return builder;
}
private static async Task<IResult> OnMessage(
HttpContext context,
OpenAIClient openAiClient,
ITwilioRestClient twilioClient,
IConfiguration configuration,
CancellationToken cancellationToken
)
{
var request = context.Request;
var session = context.Session;
await session.LoadAsync(cancellationToken).ConfigureAwait(false);
var form = await request.ReadFormAsync(cancellationToken).ConfigureAwait(false);
var receivedFrom = form["From"].ToString();
var sentTo = form["To"].ToString();
var body = form["Body"].ToString().Trim();
// ChatGPT doesn't need the phone number, just any string that uniquely identifies the user,
// hence I'm hashing the phone number to not pass in PII unnecessarily
var userId = Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(receivedFrom)));
var messages = GetPreviousMessages(session);
messages.Add(new ChatMessage(ChatRole.User, body));
var chatCompletionOptions = new ChatCompletionsOptions
{
User = userId
};
foreach(var message in messages)
chatCompletionOptions.Messages.Add(message);
var chatCompletionsResponse = await openAiClient.GetChatCompletionsAsync(
configuration["Azure:OpenAI:ModelName"],
chatCompletionOptions,
cancellationToken
);
var chatResponse = chatCompletionsResponse.Value.Choices[0].Message.Content;
messages.Add(new ChatMessage(ChatRole.Assistant, chatResponse));
SetPreviousMessages(session, messages);
await MessageResource.CreateAsync(
to: receivedFrom,
from: sentTo,
body: chatResponse,
client: twilioClient
);
return Results.Ok();
}
// Note: This method manually deserializes the chat history because
// the ChatMessage class doesn't correctly deserialize
private static List<ChatMessage> GetPreviousMessages(ISession session)
{
var jsonBytes = session.Get(PreviousMessagesKey);
if (jsonBytes == null)
{
return new List<ChatMessage>();
}
var messages = new List<ChatMessage>();
var json = JsonSerializer.Deserialize<JsonDocument>(jsonBytes);
foreach (var messageJsonObject in json.RootElement.EnumerateArray())
{
var role = messageJsonObject.GetProperty("Role").GetProperty("Label").GetString();
var content = messageJsonObject.GetProperty("Content").GetString();
var chatMessage = new ChatMessage(new ChatRole(role), content);
messages.Add(chatMessage);
}
return messages;
}
private static void SetPreviousMessages(ISession session, List<ChatMessage> messages)
{
var serializedJson = JsonSerializer.SerializeToUtf8Bytes(messages);
session.Set(PreviousMessagesKey, serializedJson);
}
private static void RemovePreviousMessages(ISession session)
=> session.Remove(PreviousMessagesKey);
}
Now the endpoint loads any previous chat messages from the session, and then adds the new SMS body. The whole conversation is passed to the chat completions API and the response is also added to the conversation, which is then persisted back into session.
Stop and start your application to try it out. Now, when I asked for a follow-up joke about cats, it knew I wanted a joke and not facts about cats.
Server sessions will automatically be removed over time, and the cookie that associates the server session with the client will also expire at some point. If a cookie does not have a set expiration date, it'll remove the cookie after 4 hours. If you want the cookie to stay around for longer, you can set the expiration date, however, Twilio may still remove it before the given expiration date.
Now that the chatbot has the context of the entire chat history, it is much more useful. However, users may still want to start from a fresh slate. Update the start of the OnMessage
method in the MessageEndpoint.cs file:
private static async Task<IResult> OnMessage(
HttpContext context,
IOpenAIService openAiService,
ITwilioRestClient twilioClient,
CancellationToken cancellationToken
)
{
var request = context.Request;
var session = context.Session;
await session.LoadAsync(cancellationToken).ConfigureAwait(false);
var form = await request.ReadFormAsync(cancellationToken);
var receivedFrom = form["From"].ToString();
var sentTo = form["To"].ToString();
var body = form["Body"].ToString().Trim();
// handle reset
if (body.Equals("reset", StringComparison.OrdinalIgnoreCase))
{
RemovePreviousMessages(session);
await MessageResource.CreateAsync(
to: receivedFrom,
from: sentTo,
body: "Your conversation is now reset.",
client: twilioClient
).ConfigureAwait(false);
return Results.Ok();
}
// ChatGPT doesn't need the phone number, just any string that uniquely identifies the user,
// hence I'm hashing the phone number to not pass in PII unnecessarily
var userId = Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(receivedFrom)));
Now users can text "reset" and the chat history will be reset.
Maximize message delivery
You can only send messages using Twilio SMS that are shorter or equal to 1600 characters, but sometimes the chat completions response will exceed that limit. If so, you'd receive an error that would look something like this:
Unhandled exception. Twilio.Exceptions.ApiException: The concatenated message body exceeds the 1600 character limit.
at Twilio.Clients.TwilioRestClient.ProcessResponse(Response response)
at Twilio.Clients.TwilioRestClient.Request(Request request)
at Twilio.Rest.Api.V2010.Account.MessageResource.Create(CreateMessageOptions options, ITwilioRestClient client)
at Twilio.Rest.Api.V2010.Account.MessageResource.Create(PhoneNumber to, String pathAccountSid, PhoneNumber from, String messagingServiceSid, String body, List`1 mediaUrl, Uri statusCallback, String applicationSid, Nullable`1 maxPrice, Nullable`1 provideFeedback, Nullable`1 attempt, Nullable`1 validityPeriod, Nullable`1 forceDelivery, ContentRetentionEnum contentRetention, AddressRetentionEnum addressRetention, Nullable`1 smartEncoded, List`1 persistentAction, Nullable`1 shortenUrls, ScheduleTypeEnum scheduleType, Nullable`1 sendAt, Nullable`1 sendAsMms, String contentSid, String contentVariables, ITwilioRestClient client)
While Twilio will accept messages shorter than or equal to 1600 characters, Twilio recommends keeping your messages below or equal to 320 characters to maximize deliverability of your messages.
To ensure your application does this, update the OnMessage
method again:
private static async Task<IResult> OnMessage(
HttpContext context,
OpenAIClient openAiClient,
ITwilioRestClient twilioClient,
IConfiguration configuration,
CancellationToken cancellationToken
)
{
var request = context.Request;
var session = context.Session;
await session.LoadAsync(cancellationToken).ConfigureAwait(false);
var form = await request.ReadFormAsync(cancellationToken).ConfigureAwait(false);
var receivedFrom = form["From"].ToString();
var sentTo = form["To"].ToString();
var body = form["Body"].ToString().Trim();
// handle reset
if (body.Equals("reset", StringComparison.OrdinalIgnoreCase))
{
RemovePreviousMessages(session);
await MessageResource.CreateAsync(
to: receivedFrom,
from: sentTo,
body: "Your conversation is now reset.",
client: twilioClient
).ConfigureAwait(false);
return Results.Ok();
}
// ChatGPT doesn't need the phone number, just any string that uniquely identifies the user,
// hence I'm hashing the phone number to not pass in PII unnecessarily
var userId = Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(receivedFrom)));
var messages = GetPreviousMessages(session);
messages.Add(new ChatMessage(ChatRole.User, body));
var chatCompletionOptions = new ChatCompletionsOptions
{
User = userId
};
foreach(var message in messages)
chatCompletionOptions.Messages.Add(message);
var chatCompletionsResponse = await openAiClient.GetChatCompletionsAsync(
configuration["Azure:OpenAI:ModelName"],
chatCompletionOptions,
cancellationToken
);
var chatResponse = chatCompletionsResponse.Value.Choices[0].Message.Content;
messages.Add(new ChatMessage(ChatRole.Assistant, chatResponse));
SetPreviousMessages(session, messages);
// 320 is the recommended message length for maximum deliverability,
// but you can change this to your preference. The max for a Twilio message is 1600 characters.
// https://support.twilio.com/hc/en-us/articles/360033806753-Maximum-Message-Length-with-Twilio-Programmable-Messaging
var responseMessages = SplitTextIntoMessages(chatResponse, maxLength: 320);
// Twilio webhook expects a response within 10 seconds.
// we don't need to wait for the SendResponse task to complete, so don't await
_ = SendResponse(twilioClient, to: receivedFrom, from: sentTo, responseMessages);
return Results.Ok();
}
Then add these two static functions to the MessageEndpoint
class:
/// <summary>
/// Splits the text into multiple strings by splitting it by its paragraphs
/// and adding them back together until the max length is reached.
/// Warning: This assumes each paragraph does not exceed the maxLength already, which may not be the case.
/// </summary>
/// <param name="text"></param>
/// <param name="maxLength"></param>
/// <returns>Returns a list of messages, each not exceeding the maxLength</returns>
private static List<string> SplitTextIntoMessages(string text, int maxLength)
{
List<string> messages = new();
var paragraphs = text.Split("\n\n");
StringBuilder messageBuilder = new();
for (int paragraphIndex = 0; paragraphIndex < paragraphs.Length - 1; paragraphIndex++)
{
string currentParagraph = paragraphs[paragraphIndex];
string nextParagraph = paragraphs[paragraphIndex + 1];
messageBuilder.Append(currentParagraph);
// + 2 for "\n\n"
if (messageBuilder.Length + nextParagraph.Length > maxLength + 2)
{
messages.Add(messageBuilder.ToString());
messageBuilder.Clear();
}
else
{
messageBuilder.Append("\n\n");
}
}
messageBuilder.Append(paragraphs.Last());
messages.Add(messageBuilder.ToString());
return messages;
}
private static async Task SendResponse(
ITwilioRestClient twilioClient,
string to,
string from,
List<string> responseMessages
)
{
foreach (var responseMessage in responseMessages)
{
await MessageResource.CreateAsync(
to: to,
from: from,
body: responseMessage,
client: twilioClient
)
.ConfigureAwait(false);
// Twilio cannot guarantee order of the messages as it is up to the carrier to deliver the SMS's.
// by adding a 1s delay between each message, the messages are deliver in the correct order in most cases.
// alternatively, you could query the status of each message until it is delivered, then send the next.
await Task.Delay(1000);
}
}
The SplitTextIntoMessages
method will split the text into paragraphs and add the paragraphs while not exceeding the recommended 320-character limit. The method returns a list of strings, each containing 1 or more paragraphs. If a paragraph is larger than 320 characters, the individual string will exceed the 320-character limit. So it doesn't guarantee each string will be less than 320 characters, but in most cases it will be.
The SendResponse
method iterates over the list of strings and sends them out one by one with a one-second delay between each. Twilio cannot guarantee that the messages will arrive in the same order as they are created. However, by putting a one-second delay between each message the order is preserved most of the time. Alternatively, you could poll the message status and wait to send the next message until the current message is delivered.
Restart your application and try asking the bot a question that will have a long response. Here's a video that shows how the bot answers the question "How do I become a .NET developer?".
The video shows how the bot responds with multiple messages, with a delay between each message, but the messages are in the correct order.
Next steps
Fantastic job! You’ve integrated Azure OpenAI's APIs with Twilio SMS to create an SMS based ChatGPT bot.
You can further improve this solution by storing the conversation history in a database instead of a server session. If you do that, you can respond to the webhook immediately, and then asynchronously without awaiting the task, do all the work including calling the chat completions API, which can take a while.
Want to experiment more with OpenAI's APIs? Here's a tutorial on how to generate AI art with DALL·E 2 by texting a Twilio phone number, and a tutorial to create a ChatGPT bot that impersonates Rick from Rick & Morty for the console.
We can't wait to see what you build. Let us know!
Niels Swimberghe is a Belgian American software engineer and technical content creator at Twilio. Get in touch with Niels on Twitter @RealSwimburger and follow Niels’ personal blog on .NET, Azure, and web development at swimburger.net.
This content originally appeared on Twilio Blog and was authored by Niels Swimberghe

Niels Swimberghe | Sciencx (2023-05-15T16:59:51+00:00) Build a ChatGPT SMS bot with Azure OpenAI Service and ASP.NET Core. Retrieved from https://www.scien.cx/2023/05/15/build-a-chatgpt-sms-bot-with-azure-openai-service-and-asp-net-core/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.