commit
84ae25878c
|
|
@ -1,4 +1,5 @@
|
|||
using BotSharp.Abstraction.Agents.Enums;
|
||||
using BotSharp.Abstraction.Conversations.Enums;
|
||||
using BotSharp.Abstraction.Repositories.Filters;
|
||||
using BotSharp.Abstraction.Users;
|
||||
|
||||
|
|
@ -47,20 +48,26 @@ public class RateLimitConversationHook : ConversationHookBase
|
|||
}
|
||||
}
|
||||
|
||||
// Check the number of conversations
|
||||
var user = _services.GetRequiredService<IUserIdentity>();
|
||||
var convService = _services.GetRequiredService<IConversationService>();
|
||||
var results = await convService.GetConversations(new ConversationFilter
|
||||
{
|
||||
UserId = user.Id,
|
||||
StartTime = DateTime.UtcNow.AddHours(-24),
|
||||
});
|
||||
var states = _services.GetRequiredService<IConversationStateService>();
|
||||
var channel = states.GetState("channel");
|
||||
|
||||
if (results.Count > rateLimit.MaxConversationPerDay)
|
||||
// Check the number of conversations
|
||||
if (channel != ConversationChannel.Phone && channel != ConversationChannel.Email)
|
||||
{
|
||||
message.Content = $"The number of conversations you have exceeds the system maximum of {rateLimit.MaxConversationPerDay}";
|
||||
message.StopCompletion = true;
|
||||
return;
|
||||
var user = _services.GetRequiredService<IUserIdentity>();
|
||||
var convService = _services.GetRequiredService<IConversationService>();
|
||||
var results = await convService.GetConversations(new ConversationFilter
|
||||
{
|
||||
UserId = user.Id,
|
||||
StartTime = DateTime.UtcNow.AddHours(-24),
|
||||
});
|
||||
|
||||
if (results.Count > rateLimit.MaxConversationPerDay)
|
||||
{
|
||||
message.Content = $"The number of conversations you have exceeds the system maximum of {rateLimit.MaxConversationPerDay}";
|
||||
message.StopCompletion = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ using BotSharp.Plugin.Twilio.Models;
|
|||
using BotSharp.Plugin.Twilio.Services;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Twilio.Http;
|
||||
|
||||
namespace BotSharp.Plugin.Twilio.Controllers;
|
||||
|
||||
|
|
@ -35,7 +36,7 @@ public class TwilioVoiceController : TwilioController
|
|||
string conversationId = $"TwilioVoice_{request.CallSid}";
|
||||
var twilio = _services.GetRequiredService<TwilioService>();
|
||||
var url = $"twilio/voice/{conversationId}/receive/0?states={states}";
|
||||
var response = twilio.ReturnInstructions("twilio/welcome.mp3", url, true);
|
||||
var response = twilio.ReturnInstructions(new List<string> { "twilio/welcome.mp3" }, url, true);
|
||||
return TwiML(response);
|
||||
}
|
||||
|
||||
|
|
@ -53,17 +54,10 @@ public class TwilioVoiceController : TwilioController
|
|||
messages.Add(text);
|
||||
await sessionManager.StageCallerMessageAsync(conversationId, seqNum, text);
|
||||
}
|
||||
|
||||
VoiceResponse response;
|
||||
if (messages.Count == 0 && seqNum == 0)
|
||||
{
|
||||
response = twilio.ReturnInstructions("twilio/welcome.mp3", $"twilio/voice/{conversationId}/receive/{seqNum}?states={states}", true, timeout: 2);
|
||||
}
|
||||
else
|
||||
if (messages.Any())
|
||||
{
|
||||
if (messages.Count == 0)
|
||||
{
|
||||
messages = await sessionManager.RetrieveStagedCallerMessagesAsync(conversationId, seqNum - 1);
|
||||
}
|
||||
var messageContent = string.Join("\r\n", messages);
|
||||
var callerMessage = new CallerMessage()
|
||||
{
|
||||
|
|
@ -82,15 +76,21 @@ public class TwilioVoiceController : TwilioController
|
|||
}
|
||||
await messageQueue.EnqueueAsync(callerMessage);
|
||||
|
||||
int audioIndex = Random.Shared.Next(1, 5);
|
||||
response = twilio.ReturnInstructions($"twilio/hold-on-{audioIndex}.mp3", $"twilio/voice/{conversationId}/reply/{seqNum}?states={states}", true, 1);
|
||||
response = new VoiceResponse()
|
||||
.Redirect(new Uri($"{_settings.CallbackHost}/twilio/voice/{conversationId}/reply/{seqNum}?states={states}"), HttpMethod.Post);
|
||||
}
|
||||
else
|
||||
{
|
||||
response = twilio.ReturnInstructions(null, $"twilio/voice/{conversationId}/receive/{seqNum}?states={states}", true);
|
||||
}
|
||||
|
||||
return TwiML(response);
|
||||
}
|
||||
|
||||
[ValidateRequest]
|
||||
[HttpPost("twilio/voice/{conversationId}/reply/{seqNum}")]
|
||||
public async Task<TwiMLResult> ReplyCallerMessage([FromRoute] string conversationId, [FromRoute] int seqNum, [FromQuery] string states, VoiceRequest request)
|
||||
public async Task<TwiMLResult> ReplyCallerMessage([FromRoute] string conversationId, [FromRoute] int seqNum,
|
||||
[FromQuery] string states, [FromQuery] string play, VoiceRequest request)
|
||||
{
|
||||
var nextSeqNum = seqNum + 1;
|
||||
var sessionManager = _services.GetRequiredService<ITwilioSessionManager>();
|
||||
|
|
@ -106,25 +106,33 @@ public class TwilioVoiceController : TwilioController
|
|||
var indication = await sessionManager.GetReplyIndicationAsync(conversationId, seqNum);
|
||||
if (indication != null)
|
||||
{
|
||||
string speechPath;
|
||||
if (indication.StartsWith('#'))
|
||||
var speechPaths = new List<string>();
|
||||
foreach (var text in indication.Split('|'))
|
||||
{
|
||||
speechPath = $"twilio/{indication.Substring(1)}";
|
||||
var seg = text.Trim();
|
||||
if (seg.StartsWith('#'))
|
||||
{
|
||||
speechPaths.Add($"twilio/{seg.Substring(1)}.mp3");
|
||||
}
|
||||
else
|
||||
{
|
||||
var textToSpeechService = CompletionProvider.GetTextToSpeech(_services, "openai", "tts-1");
|
||||
var fileService = _services.GetRequiredService<IFileStorageService>();
|
||||
var data = await textToSpeechService.GenerateSpeechFromTextAsync(seg);
|
||||
var fileName = $"indication_{seqNum}.mp3";
|
||||
await fileService.SaveSpeechFileAsync(conversationId, fileName, data);
|
||||
speechPaths.Add($"twilio/voice/speeches/{conversationId}/{fileName}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var textToSpeechService = CompletionProvider.GetTextToSpeech(_services, "openai", "tts-1");
|
||||
var fileService = _services.GetRequiredService<IFileStorageService>();
|
||||
var data = await textToSpeechService.GenerateSpeechFromTextAsync(indication);
|
||||
var fileName = $"indication_{seqNum}.mp3";
|
||||
await fileService.SaveSpeechFileAsync(conversationId, fileName, data);
|
||||
speechPath = $"twilio/voice/speeches/{conversationId}/{fileName}";
|
||||
}
|
||||
response = twilio.ReturnInstructions(speechPath, $"twilio/voice/{conversationId}/reply/{seqNum}?states={states}", true, 2);
|
||||
response = twilio.ReturnInstructions(speechPaths, $"twilio/voice/{conversationId}/reply/{seqNum}?states={states}", true);
|
||||
}
|
||||
else
|
||||
{
|
||||
response = twilio.ReturnInstructions(null, $"twilio/voice/{conversationId}/reply/{seqNum}?states={states}", true, 1);
|
||||
response = twilio.ReturnInstructions(new List<string>
|
||||
{
|
||||
$"twilio/hold-on-{Random.Shared.Next(1, 5)}.mp3",
|
||||
$"twilio/typing-{Random.Shared.Next(2, 4)}.mp3"
|
||||
}, $"twilio/voice/{conversationId}/reply/{seqNum}?states={states}", true);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -135,7 +143,7 @@ public class TwilioVoiceController : TwilioController
|
|||
}
|
||||
else
|
||||
{
|
||||
response = twilio.ReturnInstructions($"twilio/voice/speeches/{conversationId}/{reply.SpeechFileName}", $"twilio/voice/{conversationId}/receive/{nextSeqNum}?states={states}", true);
|
||||
response = twilio.ReturnInstructions(new List<string> { $"twilio/voice/speeches/{conversationId}/{reply.SpeechFileName}" }, $"twilio/voice/{conversationId}/receive/{nextSeqNum}?states={states}", true);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ namespace BotSharp.Plugin.Twilio.Services
|
|||
{
|
||||
reply = new AssistantMessage()
|
||||
{
|
||||
ConversationEnd = msg.Instruction.ConversationEnd,
|
||||
ConversationEnd = msg.Instruction?.ConversationEnd ?? false,
|
||||
Content = msg.Content,
|
||||
MessageId = msg.MessageId
|
||||
};
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ public class TwilioService
|
|||
return response;
|
||||
}
|
||||
|
||||
public VoiceResponse ReturnInstructions(string speechPath, string callbackPath, bool actionOnEmptyResult, int timeout = 3)
|
||||
public VoiceResponse ReturnInstructions(List<string> speechPaths, string callbackPath, bool actionOnEmptyResult, int timeout = 2)
|
||||
{
|
||||
var response = new VoiceResponse();
|
||||
var gather = new Gather()
|
||||
|
|
@ -80,13 +80,11 @@ public class TwilioService
|
|||
Timeout = timeout > 0 ? timeout : 3,
|
||||
ActionOnEmptyResult = actionOnEmptyResult
|
||||
};
|
||||
if (!string.IsNullOrEmpty(speechPath))
|
||||
if (speechPaths != null && speechPaths.Any())
|
||||
{
|
||||
gather.Play(new Uri($"{_settings.CallbackHost}/{speechPath}"));
|
||||
if (speechPath.Contains("hold-on-"))
|
||||
foreach (var speechPath in speechPaths)
|
||||
{
|
||||
int audioIndex = Random.Shared.Next(1, 4);
|
||||
gather.Play(new Uri($"{_settings.CallbackHost}/twilio/typing-{audioIndex}.mp3"));
|
||||
gather.Play(new Uri($"{_settings.CallbackHost}/{speechPath}"));
|
||||
}
|
||||
}
|
||||
response.Append(gather);
|
||||
|
|
|
|||
Loading…
Reference in a new issue